Imported Upstream version 0.9.6.1
authorGeoffroy Van Cutsem <geoffroy.vancutsem@intel.com>
Wed, 6 Mar 2013 15:51:47 +0000 (16:51 +0100)
committerGeoffroy Van Cutsem <geoffroy.vancutsem@intel.com>
Wed, 6 Mar 2013 15:51:47 +0000 (16:51 +0100)
85 files changed:
82802ab.c [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Documentation/mysteries_intel.txt [new file with mode: 0644]
Documentation/serprog-protocol.txt [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
a25.c [new file with mode: 0644]
arch.h [new file with mode: 0644]
at25.c [new file with mode: 0644]
atahpt.c [new file with mode: 0644]
bitbang_spi.c [new file with mode: 0644]
board_enable.c [new file with mode: 0644]
buspirate_spi.c [new file with mode: 0644]
cbtable.c [new file with mode: 0644]
chipdrivers.h [new file with mode: 0644]
chipset_enable.c [new file with mode: 0644]
cli_classic.c [new file with mode: 0644]
cli_output.c [new file with mode: 0644]
coreboot_tables.h [new file with mode: 0644]
dediprog.c [new file with mode: 0644]
dmi.c [new file with mode: 0644]
drkaiser.c [new file with mode: 0644]
dummyflasher.c [new file with mode: 0644]
en29lv640b.c [new file with mode: 0644]
flash.h [new file with mode: 0644]
flashchips.c [new file with mode: 0644]
flashchips.h [new file with mode: 0644]
flashrom.8 [new file with mode: 0644]
flashrom.c [new file with mode: 0644]
ft2232_spi.c [new file with mode: 0644]
gfxnvidia.c [new file with mode: 0644]
hwaccess.c [new file with mode: 0644]
hwaccess.h [new file with mode: 0644]
ich_descriptors.c [new file with mode: 0644]
ich_descriptors.h [new file with mode: 0644]
ichspi.c [new file with mode: 0644]
internal.c [new file with mode: 0644]
it85spi.c [new file with mode: 0644]
it87spi.c [new file with mode: 0644]
jedec.c [new file with mode: 0644]
layout.c [new file with mode: 0644]
linux_spi.c [new file with mode: 0644]
m29f400bt.c [new file with mode: 0644]
mcp6x_spi.c [new file with mode: 0644]
nic3com.c [new file with mode: 0644]
nicintel.c [new file with mode: 0644]
nicintel_spi.c [new file with mode: 0644]
nicnatsemi.c [new file with mode: 0644]
nicrealtek.c [new file with mode: 0644]
ogp_spi.c [new file with mode: 0644]
opaque.c [new file with mode: 0644]
os.h [new file with mode: 0644]
pcidev.c [new file with mode: 0644]
physmap.c [new file with mode: 0644]
pm49fl00x.c [new file with mode: 0644]
pony_spi.c [new file with mode: 0644]
print.c [new file with mode: 0644]
print_wiki.c [new file with mode: 0644]
processor_enable.c [new file with mode: 0644]
programmer.c [new file with mode: 0644]
programmer.h [new file with mode: 0644]
rayer_spi.c [new file with mode: 0644]
satamv.c [new file with mode: 0644]
satasii.c [new file with mode: 0644]
sb600spi.c [new file with mode: 0644]
serial.c [new file with mode: 0644]
serprog.c [new file with mode: 0644]
sfdp.c [new file with mode: 0644]
spi.c [new file with mode: 0644]
spi.h [new file with mode: 0644]
spi25.c [new file with mode: 0644]
sst28sf040.c [new file with mode: 0644]
sst49lfxxxc.c [new file with mode: 0644]
sst_fwhub.c [new file with mode: 0644]
stm50flw0x0x.c [new file with mode: 0644]
udelay.c [new file with mode: 0644]
util/flashrom_partial_write_test.sh [new file with mode: 0755]
util/ich_descriptors_tool/Makefile [new file with mode: 0644]
util/ich_descriptors_tool/TODO [new file with mode: 0644]
util/ich_descriptors_tool/ich_descriptors_tool.c [new file with mode: 0644]
util/z60_flashrom.rules [new file with mode: 0644]
w29ee011.c [new file with mode: 0644]
w39.c [new file with mode: 0644]
wbsio_spi.c [new file with mode: 0644]

diff --git a/82802ab.c b/82802ab.c
new file mode 100644 (file)
index 0000000..79e157a
--- /dev/null
+++ b/82802ab.c
@@ -0,0 +1,266 @@
+/*
+ * 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
+ */
+
+/*
+ * Datasheet:
+ *  - Name: Intel 82802AB/82802AC Firmware Hub (FWH)
+ *  - URL: http://www.intel.com/design/chipsets/datashts/290658.htm
+ *  - PDF: http://download.intel.com/design/chipsets/datashts/29065804.pdf
+ *  - Order number: 290658-004
+ */
+
+#include "flash.h"
+#include "chipdrivers.h"
+
+void print_status_82802ab(uint8_t status)
+{
+       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 flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t id1, id2, flashcontent1, flashcontent2;
+       int shifted = (flash->feature_bits & FEATURE_ADDR_SHIFTED) != 0;
+
+       /* Reset to get a clean state */
+       chip_writeb(flash, 0xFF, bios);
+       programmer_delay(10);
+
+       /* Enter ID mode */
+       chip_writeb(flash, 0x90, bios);
+       programmer_delay(10);
+
+       id1 = chip_readb(flash, bios + (0x00 << shifted));
+       id2 = chip_readb(flash, bios + (0x01 << shifted));
+
+       /* Leave ID mode */
+       chip_writeb(flash, 0xFF, bios);
+
+       programmer_delay(10);
+
+       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(flash, bios + (0x00 << shifted));
+       flashcontent2 = chip_readb(flash, 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;
+
+       if (flash->feature_bits & FEATURE_REGISTERMAP)
+               map_flash_registers(flash);
+
+       return 1;
+}
+
+uint8_t wait_82802ab(struct flashctx *flash)
+{
+       uint8_t status;
+       chipaddr bios = flash->virtual_memory;
+
+       chip_writeb(flash, 0x70, bios);
+       if ((chip_readb(flash, bios) & 0x80) == 0) {    // it's busy
+               while ((chip_readb(flash, bios) & 0x80) == 0) ;
+       }
+
+       status = chip_readb(flash, bios);
+
+       /* Reset to get a clean state */
+       chip_writeb(flash, 0xFF, bios);
+
+       return status;
+}
+
+int unlock_82802ab(struct flashctx *flash)
+{
+       int i;
+       //chipaddr wrprotect = flash->virtual_registers + page + 2;
+
+       for (i = 0; i < flash->total_size * 1024; i+= flash->page_size)
+               chip_writeb(flash, 0, flash->virtual_registers + i + 2);
+
+       return 0;
+}
+
+int erase_block_82802ab(struct flashctx *flash, unsigned int page,
+                       unsigned int pagesize)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t status;
+
+       // clear status register
+       chip_writeb(flash, 0x50, bios + page);
+
+       // now start it
+       chip_writeb(flash, 0x20, bios + page);
+       chip_writeb(flash, 0xd0, bios + page);
+       programmer_delay(10);
+
+       // now let's see what the register is
+       status = wait_82802ab(flash);
+       print_status_82802ab(status);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+/* chunksize is 1 */
+int write_82802ab(struct flashctx *flash, uint8_t *src, unsigned int start,
+                 unsigned int len)
+{
+       int i;
+       chipaddr dst = flash->virtual_memory + start;
+
+       for (i = 0; i < len; i++) {
+               /* transfer data from source to destination */
+               chip_writeb(flash, 0x40, dst);
+               chip_writeb(flash, *src++, dst++);
+               wait_82802ab(flash);
+       }
+
+       /* FIXME: Ignore errors for now. */
+       return 0;
+}
+
+int unlock_28f004s5(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t mcfg, bcfg, need_unlock = 0, can_unlock = 0;
+       int i;
+
+       /* Clear status register */
+       chip_writeb(flash, 0x50, bios);
+
+       /* Read identifier codes */
+       chip_writeb(flash, 0x90, bios);
+
+       /* Read master lock-bit */
+       mcfg = chip_readb(flash, 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(flash, bios + i + 2); // read block lock config
+               msg_cdbg("block lock at %06x is %slocked!\n", i, bcfg ? "" : "un");
+               if (bcfg) {
+                       need_unlock = 1;
+               }
+       }
+
+       /* Reset chip */
+       chip_writeb(flash, 0xFF, bios);
+
+       /* Unlock: clear block lock-bits, if needed */
+       if (can_unlock && need_unlock) {
+               msg_cdbg("Unlock: ");
+               chip_writeb(flash, 0x60, bios);
+               chip_writeb(flash, 0xD0, bios);
+               chip_writeb(flash, 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;
+}
+
+int unlock_lh28f008bjt(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t mcfg, bcfg;
+       uint8_t need_unlock = 0, can_unlock = 0;
+       int i;
+
+       /* Wait if chip is busy */
+       wait_82802ab(flash);
+
+       /* Read identifier codes */
+       chip_writeb(flash, 0x90, bios);
+
+       /* Read master lock-bit */
+       mcfg = chip_readb(flash, 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, 8 * 8 KB + 15 * 64 KB */
+       for (i = 0; i < flash->total_size * 1024;
+            i += (i >= (64 * 1024) ? 64 * 1024 : 8 * 1024)) {
+               bcfg = chip_readb(flash, bios + i + 2); /* read block lock config */
+               msg_cdbg("block lock at %06x is %slocked!\n", i,
+                        bcfg ? "" : "un");
+               if (bcfg)
+                       need_unlock = 1;
+       }
+
+       /* Reset chip */
+       chip_writeb(flash, 0xFF, bios);
+
+       /* Unlock: clear block lock-bits, if needed */
+       if (can_unlock && need_unlock) {
+               msg_cdbg("Unlock: ");
+               chip_writeb(flash, 0x60, bios);
+               chip_writeb(flash, 0xD0, bios);
+               chip_writeb(flash, 0xFF, bios);
+               wait_82802ab(flash);
+               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/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d511905
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..0875ee8
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,21931 @@
+------------------------------------------------------------------------
+r1564 | hailfinger | 2012-08-08 02:14:58 +0200 (Wed, 08 Aug 2012) | 5 lines
+
+Tag flashrom 0.9.6.1
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1563 | hailfinger | 2012-08-08 02:13:10 +0200 (Wed, 08 Aug 2012) | 5 lines
+
+Increase flashrom release number to 0.9.6.1
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1562 | hailfinger | 2012-08-07 13:59:59 +0200 (Tue, 07 Aug 2012) | 13 lines
+
+Fix missing #include hwaccess.h
+
+In r1549 #include "hwaccess.h" was moved to individual drivers.
+Unfortunately, flashrom.c was forgotten. This caused flashrom to falsely
+report an unknown PCI library version and big-endianness on all
+platforms.
+
+Add #include "hwaccess.h".
+Explicitly check for __FLASHROM_BIG_ENDIAN__
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1561 | stefanct | 2012-08-03 01:56:49 +0200 (Fri, 03 Aug 2012) | 6 lines
+
+Refine messages of SPI block protection disables.
+
+Make them real progress indicators with a final "done" message on success.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1560 | stefanct | 2012-08-03 01:51:28 +0200 (Fri, 03 Aug 2012) | 8 lines
+
+Clean up a25.c, at25.c, spi25.c.
+
+- introduce spi_prettyprint_status_register_atmel_at25_wpen()
+- use spi_prettyprint_status_register_bit() where possible
+- generify spi_prettyprint_status_register_bp3210 and use it in at25.c too
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1558 | hailfinger | 2012-08-03 00:00:05 +0200 (Fri, 03 Aug 2012) | 5 lines
+
+Increase flashrom release number to 0.9.6
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1557 | stefanct | 2012-07-30 21:42:33 +0200 (Mon, 30 Jul 2012) | 13 lines
+
+Remove more exit calls.
+
+This patch removes the remaining exit calls from
+ - sp_openserport
+ - sp_opensocket
+ - sp_docommand
+ - internal_init
+
+Almost all of this was done by Niklas.
+
+Signed-off-by: Niklas S?\195?\182derlund <niso@kth.se>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1556 | stefanct | 2012-07-29 04:04:21 +0200 (Sun, 29 Jul 2012) | 14 lines
+
+print_wiki: fix columns calculations.
+
+for
+- chipsets
+- boards, and
+- chips
+
+Previously the chipset columns were not uniformly divided at all,
+which led to very odd table bottoms. This patches fixes this as far
+as wiki code can do (browser rendering can still create odd effects
+because we do not define cell heights).
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1555 | stefanct | 2012-07-28 21:35:26 +0200 (Sat, 28 Jul 2012) | 13 lines
+
+Introduce enum test_state.
+
+Previously boards in the wiki were tagged either as working or as known
+bad. But we added support to various boards via board enables that were
+then never tested because the owners have not reported back. This can
+now be tagged with NT and is shown appropriately.
+
+Also, the underlying data structure indicating state was converted from
+macros to an enum while preserving original integer values and is used
+for programmers and chipsets too.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1554 | stefanct | 2012-07-28 05:17:15 +0200 (Sat, 28 Jul 2012) | 90 lines
+
+Add a bunch of new/tested stuff and various small changes 13.
+
+Tested Mainboards:
+OK:
+ - ASRock A780FullHD
+   http://www.flashrom.org/pipermail/flashrom/2012-July/009599.html
+ - ASRock 880G Pro3
+   http://www.flashrom.org/pipermail/flashrom/2012-July/009492.html
+ - ASRock N61P-S
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009316.html
+ - ASUS M2N68-VM
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009334.html
+ - ASUS M3N78 PRO
+   http://www.flashrom.org/pipermail/flashrom/2012-July/009519.html
+ - ASUS M4N68T V2
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009277.html
+ - ASUS M5A78L-M LX
+   reported by clavile on IRC
+ - ASUS P8P67 PRO (rev. 3.0)
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009188.html
+ - ASUS P8Z68-V
+   reported by Kano on IRC
+   http://paste.flashrom.org/view.php?id=1232
+ - ASUS SABERTOOTH 990FX
+   http://paste.flashrom.org/view.php?id=1214
+ - Dell Inspiron 1420
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009196.html
+ - ECS GF8200A
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009256.html
+ - GIGABYTE GA-H61M-D2H-USB3
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009333.html
+ - MSI MS-7250 (K9N SLI (rev 2.1))
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009436.html
+ - MSI MS-7676 (Z68MA-G45 (B3))
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009424.html
+ - Palit N61S
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009212.html
+
+NOT OK:
+ - ASRock H61M-ITX
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009224.html
+ - Dell Latitude E6520
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009197.html
+ - Dell Vostro 3700
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009197.html
+ - Intel DH61AG
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009417.html
+ - Intel DQ965GF
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009295.html
+ - HP/Compaq 8100 Elite CMT PC (304Bh)
+   http://paste.flashrom.org/view.php?id=1182
+ - HP Z400 Workstation (0AE4h)
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009350.html
+ - Supermicro X9DR3-F
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009422.html
+   
+
+Tested flash chips:
+ - mark AMIC A25L032 as TEST_OK_PREW (+PREW)
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009363.html
+ - mark Atmel AT25DF321A as TEST_OK_PREW (+REW)
+   http://www.flashrom.org/pipermail/flashrom/2012-July/009492.html
+ - mark Atmel AT26DF161 as TEST_OK_PR (+PR)
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009350.html
+ - mark Eon EN25QH16 as TEST_OK_PR (+PR)
+   http://www.flashrom.org/pipermail/flashrom/2012-July/009566.html
+ - mark SST SST39VF010 as TEST_OK_PREW (+W)
+   http://www.flashrom.org/pipermail/flashrom/2012-June/009425.html
+ - mark ST M25P64 as TEST_OK_PREW (+PREW)
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009332.html
+
+Tested chipset enables:
+ - Intel 3420
+   http://www.flashrom.org/pipermail/flashrom/2012-May/009332.html
+
+ - Add board enable for ASUS P5GD2-X
+   lspci: http://paste.flashrom.org/view.php?id=1234
+   write: http://paste.flashrom.org/view.php?id=1240
+
+Miscellaneous
+ - Reorder some boards in print.c.
+ - Remove broken abit URLs.
+ - Whitespace changes.
+ - Fix the maximum number of southbridge straps in the ICH descriptor structs.
+ - Refine documentation regarding ICH region lock bits.
+ - Demote verbosity of ICH Opcode reprogramming to -VV.
+ - Exclude Pony-SPI for DOS targets (missing serial support).
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1553 | stefanct | 2012-07-24 18:33:55 +0200 (Tue, 24 Jul 2012) | 7 lines
+
+Intel 7 Series fixes (addition of QM77, fixed straps printing).
+
+I looked at the datasheet to be sure that the strap names (SPI, PCI,
+LPC) are the same as on the series 5 and 6 chipsets.
+
+Signed-off-by: Helge Wagner <Helge.Wagner@ge.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1552 | hailfinger | 2012-07-22 14:01:43 +0200 (Sun, 22 Jul 2012) | 8 lines
+
+Always require the --programmer parameter on the command line if any
+flash chip access (probe/read/write/erase/...) is requested.
+
+Fix a few man page oddities as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1551 | hailfinger | 2012-07-21 19:27:08 +0200 (Sat, 21 Jul 2012) | 19 lines
+
+Automatically release I/O permissions on shutdown.
+
+get_io_perms() is renamed to rget_io_perms() and automatically registers
+a function to release I/O permissions on shutdown.
+
+Actually release I/O permissions on Solaris and iopl()-supporting
+operating systems like Linux.
+
+This patch fixes quite a few programmers which forgot to release I/O
+permissions on shutdown, and it simplifies the shutdown and error
+handling code for all others.
+
+Do not call exit(1) if I/O permissions are denied and return an error
+instead. This part of the patch was written by Niklas S?\195?\182derlund.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Signed-off-by: Niklas S?\195?\182derlund <niso@kth.se>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1550 | hailfinger | 2012-07-21 18:56:04 +0200 (Sat, 21 Jul 2012) | 6 lines
+
+Document --output in the man page.
+Add an examples section to the man page.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Paul Menzel <paulepanter@users.sourceforge.net>
+
+------------------------------------------------------------------------
+r1549 | hailfinger | 2012-07-20 22:35:14 +0200 (Fri, 20 Jul 2012) | 11 lines
+
+Hide hwaccess.h from public API.
+
+Move hwaccess.h #include from flash.h to individual drivers.
+libflashrom users need flash.h, but they do not care about hwaccess.h
+and should not see its definitions because they may conflict with
+other hardware access functions and #defines used by the libflashrom
+user.
+
+Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1548 | hailfinger | 2012-07-16 23:32:19 +0200 (Mon, 16 Jul 2012) | 12 lines
+
+Check vendor_id for PCI based external programmers.
+
+Restructure PCI device detection code.
+Rename pcidev_validate to pcidev_readbar.
+
+Note: Slight changes in behaviour are possible, especially on dual/quad
+chip NICs which appear as more than one PCI device. Found devices are no
+longer printed at _pinfo level, but rather at _pdbg level.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1547 | hailfinger | 2012-06-30 01:07:14 +0200 (Sat, 30 Jun 2012) | 8 lines
+
+Add board enable for MSI K9N SLI (MS-7250 VER:2.1)
+
+Handle PCI Device ID 0x0360 for MCP55 ISA bridge GPIO as well.
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Stefan A. Scholtz
+
+------------------------------------------------------------------------
+r1546 | hailfinger | 2012-06-19 14:06:53 +0200 (Tue, 19 Jun 2012) | 11 lines
+
+Add native SPI AAI write support to the Dediprog SF100 driver
+
+To tell the programmer how to handle the data on the spi bus, a flag in
+the fourth byte sent with the usb command is used. The second word was
+mistaken for the size of the chunks sent over usb earlier. The third
+byte (first of the second word) is now set to zero. This also adds some
+checks for the size of data chunks sent over usb.
+
+Signed-off-by: Nico Huber <nico.huber@secunet.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1545 | hailfinger | 2012-06-16 02:11:16 +0200 (Sat, 16 Jun 2012) | 8 lines
+
+Remove exit() call from show_id
+
+The only caller is able to check the return code and handle it
+correctly.
+
+Signed-off-by: Niklas S?\195?\182derlund <niso@kth.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1544 | hailfinger | 2012-06-16 02:02:27 +0200 (Sat, 16 Jun 2012) | 9 lines
+
+Add voltage change delays to dediprog driver
+
+Some investigations have shown that the original dediprog driver waits
+about 200ms after setting voltage up and before setting voltage down.
+This patch adds those delays. It helps flash chips to come up in time.
+
+Signed-off-by: Nico Huber <nico.huber@secunet.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1543 | hailfinger | 2012-06-16 00:28:12 +0200 (Sat, 16 Jun 2012) | 14 lines
+
+Let the programmer driver decide how to do AAI transfers
+
+Currently spi_aai_write() is implemented without an abstraction
+mechanism for the programmer driver. This adds another function
+pointer 'write_aai' to struct spi_programmer, which is set to
+default_spi_write_aai (renamed spi_aai_write) for all programmers
+for now.
+
+A patch which utilises this abstraction in the dediprog driver will
+follow.
+
+Signed-off-by: Nico Huber <nico.huber@secunet.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1542 | stefanct | 2012-06-14 15:08:33 +0200 (Thu, 14 Jun 2012) | 7 lines
+
+Fix setting the divisor in ft2232_spi.
+
+The patch that should have improved the clock divisor setting in r1537 made
+it much worse: the divisor used was from an uninitialized buffer.
+
+Signed-off-by: Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1541 | hailfinger | 2012-06-08 17:27:47 +0200 (Fri, 08 Jun 2012) | 11 lines
+
+Bus Pirate buffer management revamp
+
+The buffer management of the Bus Pirate driver has been revamped to use
+grow-only buffers with a reasonable initial default size so realloc()
+will not have to be called in normal operation. A side effect is the
+ability to switch to a static buffer without major hassle.
+Handle OOM gracefully.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Patrick Georgi <patrick@georgi-clan.de>
+
+------------------------------------------------------------------------
+r1540 | hailfinger | 2012-06-06 11:17:06 +0200 (Wed, 06 Jun 2012) | 11 lines
+
+Add logfile support to flashrom
+
+Usage: flashrom --output logfile.txt
+
+Logfile output has at least dbg2 verbosity or screen verbosity,
+whichever is greater.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested on Linux, Windows and FreeBSD.
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1539 | stefanct | 2012-05-21 01:32:33 +0200 (Mon, 21 May 2012) | 7 lines
+
+Add support for PMC Pm39LV512.
+
+This flash is like PMC model Pm39LV010 but capacity is 64kB.
+Model ID was already defined. PREW works for me.
+
+Signed-off-by: Ky?\195?\182sti M?\195?\164lkki <kyosti.malkki@gmail.com>
+Acked-by: Paul Menzel <paulepanter@users.sourceforge.net>
+------------------------------------------------------------------------
+r1538 | stefanct | 2012-05-16 02:15:53 +0200 (Wed, 16 May 2012) | 8 lines
+
+Remove sharplhf00l04.c.
+
+The currently unreferenced function in sharplhf00l04.c does a standard
+FWH block protection reset (writes 0 to the protection register) and a
+standard FWH block erase.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1537 | stefanct | 2012-05-16 00:58:19 +0200 (Wed, 16 May 2012) | 9 lines
+
+ft2232_spi.c: add frequency divisor parameter.
+
+This adds an optional argument when using the ft2232_spi programmer to set
+the frequency divisor. The valid values for the divisor is any even integer
+between 2 and 131072.
+
+Signed-off-by: Samir Ibrad?\197?\190i?\196?\135 <sibradzic@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1536 | hailfinger | 2012-05-15 00:54:58 +0200 (Tue, 15 May 2012) | 12 lines
+
+Convert printf to msg_* where appropriate.
+Clean up cli_output.c to be more readable.
+Use enum instead of #define for message levels.
+Kill a few exit(0) calls.
+Print the command line arguments in verbose mode.
+Move actions (--list-supported etc.) after argument sanity checks.
+Reduce the number of code paths which have their own
+programmer_shutdown().
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1535 | stefanct | 2012-05-14 03:51:46 +0200 (Mon, 14 May 2012) | 7 lines
+
+Add support for Eon EN25QH32.
+
+Its ID was spotted in an descriptor region update by Jetway:
+http://paste.flashrom.org/view.php?id=1217
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1534 | stefanct | 2012-05-08 00:12:16 +0200 (Tue, 08 May 2012) | 8 lines
+
+dummyflasher.c: add support for SFDP by adding a new emulator chip: MX25L6436
+
+The chip features a complete 1.0 SFDP JEDEC flash parameter table and also a
+vendor-specific extension table (defining voltages, lock bits etc).
+NB: the MX25L6436 uses the same RDID as the MX25L6405.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1533 | hailfinger | 2012-05-07 00:48:01 +0200 (Mon, 07 May 2012) | 9 lines
+
+Add Winbond W836xx SuperI/O detection.
+Add ITE IT8707F/IT8710F detection.
+
+Note that we autodetect those chips, but we don't handle their flash
+translation features automatically yet.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1532 | stefanct | 2012-05-06 19:03:40 +0200 (Sun, 06 May 2012) | 4 lines
+
+dummyflasher: Add a status register to SPI chips.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>  
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1531 | stefanct | 2012-05-06 17:11:26 +0200 (Sun, 06 May 2012) | 4 lines
+
+Refine reprogram_opcode_on_the_fly to indicate wrong readcnt/writecnt combinations.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1530 | mkarcher | 2012-05-05 22:53:59 +0200 (Sat, 05 May 2012) | 4 lines
+
+Add manpage entry for pony_spi
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1529 | hailfinger | 2012-05-05 22:43:42 +0200 (Sat, 05 May 2012) | 6 lines
+
+Function to enable the flash interface on w83697 family SuperIO chips.
+Not hooked up to the superio detection framework yet.
+
+Signed-off-by: David Borg <borg.db@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1528 | stefanct | 2012-05-02 22:08:01 +0200 (Wed, 02 May 2012) | 22 lines
+
+spi25.c: Refactor spi_write_status_register helpers.
+
+In r1115 "Write protection handling for Atmel AT25*" the old spi_write_status_register
+function was duplicated to send WREN and EWSR commands respectively controlled
+by a new common wrapper function spi_write_status_register without a reason.
+Both functions' resulting code is  equal apart from the opcode used. The code
+itself does also differ in the macros used, but their value (apart from the opcode)
+is equal. This patch adds a new parameter for the opcode to the helper function
+which allows removal of the other one. This relies on the fact that EWSR and WREN
+have the same INSIZE and OUTSIZE though. If that is really seen as an issue, the
+sizes could be made parameters too.
+
+This patch also changes the wrapper so that it no longer sets the feature bits
+of the struct flash(ctx) argument. This may result in changed output, because it
+no longer implicitly disables the debug message in following executions. Since
+almost all chips had their feature bits fixed in the previous commit, this is
+a minor problem.
+
+Also, spi_write_status_enable has been dead code since r658 or so. Remove it.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1527 | stefanct | 2012-05-02 22:07:57 +0200 (Wed, 02 May 2012) | 28 lines
+
+Tag all EWSR chips correctly.
+
+All SPI chips without a WRSR feature bit set were evaluated except the
+Sanyo LF25FW203A for which no datasheet is available.
+
+The following list includes all SPI-capable chips that still have no
+WRSR feature bit set:
+ - AT26DF041
+ - AT45CS1282
+ - AT45DB011D
+ - AT45DB021D
+ - AT45DB041D
+ - AT45DB081D
+ - AT45DB161D
+ - AT45DB321C
+ - AT45DB321D
+ - AT45DB642D
+
+All of them have no write function set and can be therefore ignored
+for now.
+
+Apart from those the generic chips are also not tagged. The opaque
+flash interface should not be affected. The SFDP dummy chip is
+changed to explicitly set EWSR if it can't deduce it dynamically.
+The vendor detecting generic chips can't write anyway.
+
+Signed-off-by: Steven Zakulec <spzakulec@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1526 | stefanct | 2012-05-02 21:48:21 +0200 (Wed, 02 May 2012) | 9 lines
+
+Add board enable for ASUS P5BV-R.
+
+These are used in ASUS RS120-E5/PA2 servers.
+
+GPIO pin discovered, patch prepared and
+Tested-by: Geoffrey McRae
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1525 | mkarcher | 2012-05-01 01:11:06 +0200 (Tue, 01 May 2012) | 8 lines
+
+Add serial port bitbanging code
+
+This adds the pony_spi driver which supports the SI_Prog adapter, which
+is commonly used for SPI chips with PonyProg 2000, and a custom adapter
+called "SERBANG" which differs in the logic of two pins.
+
+Signed-off-by: Virgil-Adrian Teaca <darkstarlinux@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1524 | stefanct | 2012-04-27 22:41:23 +0200 (Fri, 27 Apr 2012) | 87 lines
+
+Add a bunch of new/tested stuff and various small changes 12.
+
+Tested Mainboards:
+OK:
+ - ASUS M4A785T-M
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009118.html
+ - ASUS P5VD2-MX
+   http://www.flashrom.org/pipermail/flashrom/2012-March/009014.html
+ - ASUS P8Z68-V PRO/GEN3
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009086.html
+ - Bachmann electronic OT200
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009094.html
+ - Biostar N61PB-M2S
+   http://www.flashrom.org/pipermail/flashrom/2012-March/008958.html
+ - GIGABYTE GA-H61M-D2-B3
+   http://www.flashrom.org/pipermail/flashrom/2012-March/009002.html
+ - MSI MS-7740 (H61MA-E35(B3))
+   http://www.flashrom.org/pipermail/flashrom/2012-March/008985.html
+ - Tyan S2875 (Tiger K8W)
+   http://www.flashrom.org/pipermail/flashrom/2012-March/008986.html
+ - ZOTAC nForce 630i Supreme (N73U-Supreme)
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009073.html
+ - ZOTAC ZBOX AD02 (PLUS)
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009047.html
+NOT OK:
+ - ASRock H67M
+   http://www.flashrom.org/pipermail/flashrom/2012-March/008909.html
+ - ASUS P8P67 LE
+   http://paste.flashrom.org/view.php?id=1097
+ - ASUS Maximus IV Extreme
+   http://www.flashrom.org/pipermail/flashrom/2012-March/009033.html
+ - Biostar H61MU3
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008832.html
+ - Biostar M7VIQ
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008863.html
+ - Dell Inspiron 580
+   http://www.flashrom.org/pipermail/flashrom/2012-March/008888.html
+ - Dell Vostro 460
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009144.html
+ - Fujitsu-Siemens CELSIUS W410 (D3062-A1)
+   http://www.flashrom.org/pipermail/flashrom/2012-March/008987.html
+ - EPoX EP-3PTA
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009043.html
+ - HP XW6400
+   http://www.flashrom.org/pipermail/flashrom/2012-March/009006.html
+ - HP XW9300
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008862.html
+ - Intel DG965OT
+   http://paste.flashrom.org/view.php?id=1096
+ - Intel DN2800MT (Marshalltown)
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009095.html
+ - Lenovo T420
+   http://paste.flashrom.org/view.php?id=1095
+ - Lenovo X1
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009135.html
+ - MSI GF615M-P33
+   http://www.flashrom.org/pipermail/flashrom/2012-March/008956.html
+
+Tested flash chips:
+ - mark EN25Q32(A/B) as TEST_OK_PROBE (+P)
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008832.html
+ - mark S25FL032A as TEST_OK_PR (+PR)
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009105.html
+ - mark AT25DF161 as TEST_OK_PROBE (+P)
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009095.html
+ - mark SST as TEST_OK_PREW (+EW)
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009094.html
+
+Tested chipset enables:
+ - H61 (various reports)
+ - SiS 755
+   http://www.flashrom.org/pipermail/flashrom/2012-April/009072.html
+
+ - Fix compilation of ich_descriptor_tool which was broken since r1492.
+ - Add Documentation regarding unlocking the ME region on Intel chipsets.
+ - Fix reading the flash descriptor via FDOC/FDOD and prettyprinting of the
+   descriptor on boards with 5 active regions.
+ - Reorder some boards in print.c.
+ - Add Intel 7 Series (Panther Point) PCI IDs.
+ - Add preliminary PCI IDs for future Intel chipsets (DH89xxCC and Lynx Point)
+   see https://lkml.org/lkml/2012/2/20/467
+ - Change the message for untested chipsets to send only after an attempt to
+   update the firmware with flashrom.
+ - Fix warnings in ich_descriptor_tool's build.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1523 | stefanct | 2012-04-15 16:09:16 +0200 (Sun, 15 Apr 2012) | 6 lines
+
+Check for duplicate -i arguments.
+
+And a tiny cleanup.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1522 | uwe | 2012-04-15 15:16:32 +0200 (Sun, 15 Apr 2012) | 9 lines
+
+Add support for for the Atmel AT49F040 chip.
+
+Chip features an optional permanent boot block write protection.
+
+Signed-off-by: David Borg <borg.db@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1521 | uwe | 2012-04-15 00:51:40 +0200 (Sun, 15 Apr 2012) | 11 lines
+
+Add support for the Eon EN29LV640B chip.
+
+This chip needs special command sequences in 8 bit mode. Also, 8 bit
+programming needs actually 16bit double byte program.
+
+The chip is found on the Bifferos Bifferboard, for example.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1520 | uwe | 2012-04-14 23:59:23 +0200 (Sat, 14 Apr 2012) | 13 lines
+
+Add GigaDevice GD25QXX series support.
+
+http://www.gigadevice.com/Product/SPI.php?WebPageTypeId=98&WebPageTypeId2=151&WebPageTypeId3=134
+
+The GD25Q80 has been successfully tested, the other ones are marked as
+untested for now.
+
+http://www.flashrom.org/pipermail/flashrom/2012-March/009028.html
+
+Signed-off-by: Justin Chevrier <jchevrier@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1519 | uwe | 2012-04-14 23:06:31 +0200 (Sat, 14 Apr 2012) | 9 lines
+
+Minor NetBSD/DragonFly/pkgsrc build instruction update.
+
+Add -I/usr/pkg/include to NetBSD/Dragon Fly build example CPPFLAGS.
+This is needed to pick up libftdi.
+
+Signed-off-by: Jonathan A. Kollasch <jakllsch@kollasch.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1518 | uwe | 2012-04-14 23:04:03 +0200 (Sat, 14 Apr 2012) | 10 lines
+
+Add support for the Numonyx N25Q064 chip.
+
+All operations were successfully tested.
+http://www.flashrom.org/pipermail/flashrom/2012-April/009048.html
+
+Signed-off-by: Niklas S?\195?\182derlund <niklas.soderlund@ericsson.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1517 | stefanct | 2012-03-13 01:18:19 +0100 (Tue, 13 Mar 2012) | 8 lines
+
+Make the presence of Linux SPI headers mandatory for linux_spi.
+
+This solution is copied from ft2232_spi and is equally hacky.
+Thanks to M.K. for investigating the history of <linux/spi/spidev.h>, which
+led to a hopefully more robust check.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1516 | stefanct | 2012-03-10 20:22:13 +0100 (Sat, 10 Mar 2012) | 9 lines
+
+Add (untested) board enable for ASUS TUSL2-C
+
+Primary IDs SMBus controller, secondary IDs MCH.
+The reverse engineering was done by Michael Karcher.
+?\208?\144?\208?\189?\208?\180?\209?\128?\208?\181?\208?\185 ?\208?\162?\208?\184?\208?\188?\208?\184?\209?\128?\208?\176?\208?\181?\208?\178 <dark_prof@mail.ru> reported the problem, but did not
+reply (yet) to our propsed fix.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1514 | hailfinger | 2012-03-08 22:58:40 +0100 (Thu, 08 Mar 2012) | 5 lines
+
+Increase flashrom release number to 0.9.5.2
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1513 | mkarcher | 2012-03-06 23:17:06 +0100 (Tue, 06 Mar 2012) | 11 lines
+
+Prevent submission of empty read requests in linux_spi.
+
+The submission of zero-sized read requests in a write-only transaction
+fails at least for omap2_mcspi drivers and is pointless in general.
+
+This patch does not address the implementation of zero-sized writes (which
+would need to skip the write command), as there are no flash transactions
+not starting with a command.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1512 | stefanct | 2012-03-03 19:09:33 +0100 (Sat, 03 Mar 2012) | 11 lines
+
+linux_spi.c: set SPI mode, bit order and bits per word on init.
+
+Previously we relied on a correctly set up state.
+
+Also, we start to rely on the shutdown function for cleanup after
+registering it, i.e. we no longer explicitly call close(fd) after
+register_shutdown().
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Tested-by: Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1511 | hailfinger | 2012-03-01 23:38:27 +0100 (Thu, 01 Mar 2012) | 21 lines
+
+Fix parallel-style programmer access from ITE IT87/Winbond W83627 SPI
+
+The ITE IT87 SPI driver uses a trick to speed up reading and writing:
+If a flash chip is 512 kByte or less, the flash chip can be completely
+mapped in memory and both read and write accesses are faster that way.
+The current IT87 SPI code did use the parallel programmer interface for
+memory mapped reads and writes, but that's the wrong abstraction. It has
+been fixed to use mmio_read*/mmio_write* for that purpose.
+
+The Winbond W83627 SPI driver uses the same trick in its read path for
+all supported chip sizes. Fix it the same way.
+
+Switch internal_chip_readn to use mmio_readn as proper abstraction.
+
+Kudos to Michael Karcher for spotting the bugs.
+
+Reported-by: Johan Svensson <flashrom.js@crypt.se>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Tested-by: Johan Svensson <flashrom.js@crypt.se>
+
+------------------------------------------------------------------------
+r1510 | stefanct | 2012-02-27 20:44:16 +0100 (Mon, 27 Feb 2012) | 4 lines
+
+nicintel_spi.c: check if write enable is really set (and minor comment changes).
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1508 | hailfinger | 2012-02-26 00:39:29 +0100 (Sun, 26 Feb 2012) | 5 lines
+
+Increase flashrom release number to 0.9.5.1
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1507 | hailfinger | 2012-02-25 23:50:21 +0100 (Sat, 25 Feb 2012) | 7 lines
+
+Support Debian/kFreeBSD
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Robert Millan <rmh@debian.org>
+Tested-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1506 | hailfinger | 2012-02-25 00:49:30 +0100 (Sat, 25 Feb 2012) | 11 lines
+
+SFDP: Fetch parameter table in a more portable way
+
+SFDP parameter table reads expect a dummy byte between written data
+(opcode+address) and read data on the SPI bus. Read that dummy byte
+instead of writing it to be compatible with all programmer drivers.
+Reduce SFDP parameter table read chunk size from 8 to 2 to handle
+programmers with small readcount limits.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1505 | stefanct | 2012-02-22 01:14:14 +0100 (Wed, 22 Feb 2012) | 19 lines
+
+Fix SFDP probing.
+
+sfdp_add_uniform_eraser checks for existing erasers. Due to a bug it
+looked for eraser slots that have no erase functions set instead of
+those that have one set.
+
+Postpone adding an erase function for the special 4k block erase
+opcode until we know the flash chip size and add an additional check
+to sfdp_add_uniform_eraser.
+
+Fix the output of the parameter table contents.
+
+This patch fixes the index used to retrieve the eraser types, which
+was off one double word.
+
+Refine some messages and add a few further debugging prints.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1503 | hailfinger | 2012-02-18 03:34:58 +0100 (Sat, 18 Feb 2012) | 5 lines
+
+Increase flashrom release number to 0.9.5
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1502 | stefanct | 2012-02-17 21:03:37 +0100 (Fri, 17 Feb 2012) | 12 lines
+
+Add a bunch of new/tested stuff and various small changes 11
+
+Tested Mainboards:
+NOT OK:
+ - HP dc7800
+   http://paste.flashrom.org/view.php?id=1084
+
+ - add "Low Profile Desktop" to our dmi whitelist
+ - fix print_wiki (broken since r1488)
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1501 | stefanct | 2012-02-17 15:51:15 +0100 (Fri, 17 Feb 2012) | 14 lines
+
+Add board enable for ASUS OPLX-M.
+
+The vendor enable does some other funky stuff with MTRRs/MSRs, SMIs,
+cache and legacy ISA address forward twiddling. I would only use
+this patch to read and verify the existing contents, just to be safe.
+
+The PCI IDs of the onboard devices do contain no subsystem IDs at all.
+
+Probing and reading was
+Tested-by: Ville Skytt?\195?\164 <ville.skytta@iki.fi>
+See http://www.flashrom.org/pipermail/flashrom/2010-October/005256.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1500 | stefanct | 2012-02-17 15:51:04 +0100 (Fri, 17 Feb 2012) | 24 lines
+
+Add support for SFDP (JESD216).
+
+Similar to modules using the opaque programmer framework (e.g. ICH Hardware
+Sequencing) this uses a template struct flashchip element in flashchips.c with
+a special probe function that fills the obtained values into that struct.
+
+This allows yet unknown SPI chips to be supported (read, erase, write) almost
+as if it was already added to flashchips.c.
+
+Documentation used:
+http://www.jedec.org/standards-documents/docs/jesd216 (2011-04)
+W25Q32BV data sheet Revision F (2011-04-01)
+EN25QH16 data sheet Revision F (2011-06-01)
+MX25L6436E data sheet Revision 1.8 (2011-12-26)
+
+Tested-by: David Hendricks <dhendrix@google.com>
+on W25Q64CV + dediprog
+Tested-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+on a 2010 MX25L6436E with preliminary (i.e. incorrect) SFDP implementation + serprog
+
+Thanks also to Michael Karcher for his comments and preliminary review!
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1499 | stefanct | 2012-02-16 22:07:07 +0100 (Thu, 16 Feb 2012) | 109 lines
+
+Add a bunch of new/tested stuff and various small changes 10
+
+Tested mainboards:
+OK:
+ - ABIT A-S78H
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008603.html
+ - ASRock AM2NF6G-VSTA
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008534.html
+ - ASUS KFSN4-DRE/SAS
+   reported by ted on IRC
+ - ASUS M2A-VM (HDMI variant)
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008509.html
+ - ASUS M4N78 PRO
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008598.html
+ - ASUS P5K-V
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008737.html
+ - ASUS P5KPL-CM
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008522.html
+ - ASUS P5N7A-VM
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008508.html
+ - ASUS P5QPL-AM
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008557.html
+ - ECS GF7100PVT-M3
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008412.html
+ - ECS K7SEM
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008362.html
+ - ECS P4M800PRO-M V2.0
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008478.html
+ - Gigabyte 880GMA-USB3
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008715.html
+ - Gigabyte GA-EP31-DS3L
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008601.html
+ - Gigabyte GA-X58A-UDR3
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008572.html
+ - Gigabyte GA-Z68XP-UD3
+   http://paste.flashrom.org/view.php?id=1058
+ - HP ProLiant N40L
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008650.html
+ - MSI MS-7309 (K9N6PGM2-V2)
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008441.html
+ - MSI MS-7548 (Aspen-GL8E used in HP Pavilion a6750f)
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008666.html
+ - MSI MS-7676 (H67MA-ED55(B3))
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008547.html
+ - PC Engines Alix.6f2
+   Reported by Philip Prindeville on IRC
+ - Shuttle AV18E2
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008459.html
+ - Supermicro X8DTE-F
+   http://www.flashrom.org/pipermail/flashrom/2011-November/008304.html
+ - Supermicro X8DTT-HIBQF
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008520.html
+NOT OK:
+ - ASUS P8H61-M LE/USB3
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008491.html
+ - ASUS P8H67-M PRO
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008321.html
+ - ASUS P8Z68-V PRO
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008469.html
+ - Clevo P150HM (laptop)
+   http://www.flashrom.org/pipermail/flashrom/2012-February/008717.html
+ - Intel D425KT
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008600.html
+ - Supermicro X9SCA-F
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008313.html
+
+Tested flash chips:
+ - mark AT29C512 as TEST_OK_PREW
+   http://paste.flashrom.org/view.php?id=977
+ - mark M25P40 as TEST_OK_PREW
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008351.html
+ - mark M25PE80 as TEST_OK_PREW
+   http://paste.flashrom.org/view.php?id=1061
+ - mark MX25L6405 as TEST_OK_PREW
+   tested myself with an MX25L6436E variant on serprog
+ - mark W39V080A as TEST_OK_PREW
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008509.html
+
+Tested chipsets:
+ - SiS 730 (:0730)
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008362.html
+ - NVIDIA MCP61 (:03e0)
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008534.html
+ - NVIDIA MCP73 (:07d7)
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008412.html
+ - NVIDIA MCP79 (:0aac)
+   http://www.flashrom.org/pipermail/flashrom/2012-January/008508.html
+ - VIA VT82C69x (0691) and VT82C686A/B (:0686)
+   http://www.flashrom.org/pipermail/flashrom/2011-December/008459.html
+
+ - AMD's SB950 (and presumably also SB920) have the same PCI ID as previous
+   generations, hence change the chipset enable device string. Thanks to
+   Christian Ruppert for the suggestion.
+ - Fix the board enable of the abit NF-M2 nView which had the IDs of its onboard
+   graphics card in its pattern. Change this to the LPC controller.
+ - Intel X79 SPI registers are identical to 6 Series', so use the chipsetenable
+   wrapper of it (enable_flash_pch6).
+ - Fix two paranoid checks for address < 0 in ichspi.c which became futile (and
+   generate clang warnings) with the unsignify patch committed in r1470.
+ - Rename AT25DF641 to AT25DF641(A). They are almost idencical, but could
+   be distinguished by an extended RDID probe (Atmel's patented EDI procedure),
+   which we do not support yet, hence handle them as one model for now.
+ - Source format fixes and typos
+
+the addition of the ASRock AM2NF6G-VSTA to print.c is
+Signed-off-by: Paul Menzel <paulepanter@users.sourceforge.net>
+everything else is
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1498 | hailfinger | 2012-02-16 22:00:27 +0100 (Thu, 16 Feb 2012) | 8 lines
+
+Document and enable the linux_spi driver
+
+The linux_spi driver is now enabled by default on Linux.
+A man page entry and a line in --list-supported output have been added.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1497 | stefanct | 2012-02-16 21:55:27 +0100 (Thu, 16 Feb 2012) | 18 lines
+
+Manpage improvements.
+
+The sections describing the various options of the internal and dummy
+programmers have grown out of proportions. This patch adds some headlines
+to devide the unrelated topics a bit (with .TP commands). The previous indented
+paragraphs for the various programmers were transformed to subsections (.SS).
+
+Also, rephrase the documention related to laptops completely to make it
+less redundant and more informative.
+Document the laptop=this_is_not_a_laptop internal programmer parameter
+
+Change the contact info in the bugs section by removing the trac
+reference and adding IRC (and the pastebin) instead.
+
+Remove some superfluous white space and a .RE (restore indentation) command.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1496 | hailfinger | 2012-02-16 21:31:25 +0100 (Thu, 16 Feb 2012) | 18 lines
+
+Reenable forced read
+
+Forced read functionality was disabled when programmer registration was
+merged in r1475.
+
+We now support registering more than one controller at once for each bus
+type. This can happen e.g. if one SPI controller has an attached flash
+chip and one controller doesn't. In such a case we rely on the probe
+mechanism to find exactly one chip, and the probe mechanism will
+remember which controller/bus the flash chip is attached to. A forced
+read does not have the luxury of knowing which compatible controller to
+use, so this case is handled by always picking the first one. That may
+or may not be the correct one, but there is no way (yet) to specify
+which controller a flash chip is attached to.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1495 | hailfinger | 2012-02-16 02:43:06 +0100 (Thu, 16 Feb 2012) | 8 lines
+
+Workaround missing %hhx support in MinGW sscanf
+
+MinGW uses standard Windows C libraries and those apparently don't
+support %hhx for sscanf into a uint8_t. SCNx8 isn't available either.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1494 | stefanct | 2012-02-16 02:13:00 +0100 (Thu, 16 Feb 2012) | 10 lines
+
+ichspi.c: warn user and disable writes when a protected address range is detected.
+
+This includes not only the notorious read-only flash descriptors and locked ME
+regions, but also the more rarely used PRs (Protected Ranges).
+The user can enforce write support by specifying ich_spi_force=yes in the
+programmer options, but we don't tell him the exact syntax interactively. He
+has to read it up in the man page.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1493 | stefanct | 2012-02-16 00:40:23 +0100 (Thu, 16 Feb 2012) | 15 lines
+
+Warn of one-time programmable (OTP) memory
+
+Some flash chips contain OTP memory that we cannot read or write (yet). This
+prohibits us from cloning them, hence warn the user if we detect it. Not all
+variations of the tagged chips contain OTP memory. They are often only
+enabled on request or have there own ordering numbers. There is usually no
+way to distinguish them. Because this is a supposedly seldomly used feature
+the warning is shown in with dbg verbosity.
+
+The manpage is extended to describe the backgrounds a bit.
+
+This patch is based on the idea and code of Daniel Lenski.
+Signed-off-by: Daniel Lenski <dlenski@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1492 | hailfinger | 2012-02-13 01:35:35 +0100 (Mon, 13 Feb 2012) | 11 lines
+
+Support compilation for the ARM architecture (little-endian only).
+
+Note: The internal programmer will abort during processor check. This is
+intentional.
+The other hardware drivers (except those using port I/O) should work.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: David Hendricks <dhendrix@google.com>
+Tested-by: Timo Juhani Lindfors <timo.lindfors@iki.fi>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1491 | mkarcher | 2012-02-12 01:13:14 +0100 (Sun, 12 Feb 2012) | 9 lines
+
+Board enable for TriGem Anaheim-3
+
+lspci: http://paste.flashrom.org/view.php?id=1069
+flashrom -V: http://paste.flashrom.org/view.php?id=1072
+flashrom -w: http://paste.flashrom.org/view.php?id=1073
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+(ack via IRC Feb 11, 23:14 GMT)
+------------------------------------------------------------------------
+r1490 | hailfinger | 2012-02-09 00:28:54 +0100 (Thu, 09 Feb 2012) | 23 lines
+
+SPI command black-/ignorelisting for the flash chip emulator in the dummy programmer
+
+Usage:
+flashrom -p dummy:spi_blacklist=commandlist
+flashrom -p dummy:spi_ignorelist=commandlist
+
+If commandlist is 0302, flashrom will refuse (blacklist) or ignore
+(ignorelist) command 0x03 (READ) and command 0x02 (WRITE). The
+commandlist can be up to 512 bytes (256 commands) long.
+Specifying flash chip emulation is a good idea to get useful results.
+
+Very useful for testing corner cases if you don't own a locked down
+Intel chipset and want to simulate such a thing.
+
+Example usage:
+dd if=/dev/zeros bs=1024k count=4 of=dummy_simulator.rom
+dd if=/dev/urandom bs=1024k count=4 of=randomimage.rom
+flashrom -p dummy:emulate=SST25VF032B,image=dummy_simulator.rom,\
+spi_blacklist=20,spi_ignorelist=52 -w randomimage.rom -V
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1489 | stefanct | 2012-02-07 22:29:48 +0100 (Tue, 07 Feb 2012) | 6 lines
+
+Add support for RDC R6030 chipset
+
+Tested on Bifferboard.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1488 | stefanct | 2012-02-03 23:32:09 +0100 (Fri, 03 Feb 2012) | 13 lines
+
+print*.c: Refine the do not count nor print generic flash chip entries conditions.
+
+Previously only the generic "unknown XXXX SPI chips" were ignored (because their
+name started with "unknown".
+This patch adds also all chips whose vendor starts with "Unknown" (none so far)
+and "Programmer" (currently used by the opaque flash chip framework) .
+A patch will add the SFDP chip template with an "Unknown" vendor field later.
+
+Rationale: these entries do not contain any useful information when shown in -L
+or wiki output. It would be better to add them to a general feature section or similar.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1487 | stefanct | 2012-01-31 07:51:56 +0100 (Tue, 31 Jan 2012) | 8 lines
+
+Add board enable for the MSC Q7 Tunnel Creek board
+
+This patch adds a generic phase 2 board enable that does nothing but set
+is_laptop to 0 to circumvent an erroneous laptop detection due to ambigous
+DMI chassis information.
+
+Signed-off-by: Ingo Feldschmid <ifel@msc-ge.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1486 | stefanct | 2012-01-19 18:50:32 +0100 (Thu, 19 Jan 2012) | 11 lines
+
+Add board enable for AOpen i945GMx-VFX (used in FCS ESPRIMO Q5010)
+
+Typical AWARD enable structure with an ICH GPIO board enable.
+This board seems also to be known as D2544-B1.
+
+Success report:
+http://www.flashrom.org/pipermail/flashrom/2012-January/008590.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Tested-by: Oliver Rath <rath@mglug.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1485 | hailfinger | 2012-01-12 14:58:43 +0100 (Thu, 12 Jan 2012) | 15 lines
+
+Reorder list of options to test
+
+If a chip is unknown the user is asked to test and report the result to
+the mailing list. Having `-VE` listed as the last option can result in
+an unbootable system for users not knowing what the command does, since
+rebooting the system after that command is fatal since the flash chip is
+empty. Example report at
+http://www.flashrom.org/pipermail/flashrom/2012-January/008551.html
+
+Reorder the options to prevent such accidents in the future.
+Suggested by Idwer Vollering.
+
+Signed-off-by: Paul Menzel <paulepanter@users.sourceforge.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1484 | hailfinger | 2012-01-11 03:10:11 +0100 (Wed, 11 Jan 2012) | 11 lines
+
+Postpone layout file reading
+
+Layout file reading should happen after option parsing like all other
+file accesses.
+Guard against multiple --layout parameters.
+
+Followup fix for r1483: Remove -m short option from getopt.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1483 | hailfinger | 2012-01-04 01:48:27 +0100 (Wed, 04 Jan 2012) | 22 lines
+
+Replace --mainboard with -p internal:mainboard
+
+--mainboard is a relic from a time before external programmers and makes
+the CLI inconsistent.
+Use a programmer parameter instead and free up the short option -m.
+
+NOTE:
+The --list-supported-wiki output changed to use -p internal:mainboard=
+instead of -m
+The --list-supported output changed the heading of the mainboard list
+from
+
+Vendor Board   Status  Required option
+to
+Vendor Board   Status  Required value for
+                       -p internal:mainboard=
+
+Fix lb_vendor_dev_from_string() not to write to the supplied string.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1482 | stefanct | 2011-12-25 10:12:16 +0100 (Sun, 25 Dec 2011) | 20 lines
+
+Add deferred --image processing
+
+The general idea and most of the code are based on the following
+commits in the chromiumos flashrom tree:
+
+8fc0740356ca15d02fb1c65ab43b10844f148c3b
+bb9049c66ca55e0dc621dd2c70b5d2cb6e5179bf
+Signed-off-by: Louis Yung-Chieh Lo <yjlou@chromium.org>
+
+and the main part:
+d0ea9ed71e7f86bb8e8db2ca7c32a96de25343d8
+Signed-off-by: David Hendricks <dhendrix@chromium.org>
+
+This implementation does not defer the processing until doit(), but after the
+argument parsing loop only (doit() should not contain argument checks).
+
+This allows to specify -i and -l parameters in any order.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: David Hendricks <dhendrix@google.com>
+------------------------------------------------------------------------
+r1481 | stefanct | 2011-12-25 10:07:59 +0100 (Sun, 25 Dec 2011) | 10 lines
+
+layout: change return type and name of find_next_included_romentry
+
+ - rename from find_next_included_romentry to get_next_included_romentry
+ - return a pointer to a rom_entry instead of just its index.
+   this relieves the (single existing) caller from directly accessing the
+   data structure holding the entries hence improving segregation and
+   readability.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1480 | stefanct | 2011-12-24 01:00:32 +0100 (Sat, 24 Dec 2011) | 23 lines
+
+Add ich_descriptor_tool to decode all flash descriptors stored in a flash dump file
+
+This patch adds an external utility that shares most of the existing descriptor
+decoding source code. Additionally to what is available via FDOC/FDOD this
+allows to access:
+ - the softstraps which are used to configure the chipset by flash content
+   without the need for BIOS routines. on ICH8 it is possible to read those
+   with FDOC/FDOC too, but this was removed in later chipsets.
+ - the ME VSCC (Vendor Specific Component Capabilities) table. simply put,
+   this is an SPI chip database used to figure out the flash's capabilities.
+ - the MAC address stored in the GbE image.
+
+Intel thinks this information should be confidential for ICH9 and up, but
+references some tidbits in their public documentation.
+This patch includes the human-readable information for ICH8, Ibex Peak
+(5 series) and Cougar Point (6 series); the latter two were obtained from
+leaked "SPI Flash Programming Guides" found by google. Data regarding ICH9
+and 10 is unknown to us yet. It can probably found in:
+"Intel?\194?\174 ICH7, ICH8, ICH9 and ICH10 ?\226?\128?\148 SPI Family Flash Programming Guide"
+Information regarding the upcoming Panther Point chipset is also not included.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Matthias Wenzel <bios@mazzoo.de>
+------------------------------------------------------------------------
+r1479 | mkarcher | 2011-12-23 00:27:03 +0100 (Fri, 23 Dec 2011) | 12 lines
+
+Fix programmer-centric probe (patch v2)
+
+As reported by Stefan Tauner on IRC, the new programmer-centric logic
+is broken by re-using occupied members of the flashes array when changing
+to the next programmer. This fixes it.
+
+patch v2:
+  prevent probing one chip per programmer even if the array is full. Using
+  a do-while loop was a bad idea.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1478 | hailfinger | 2011-12-20 03:08:14 +0100 (Tue, 20 Dec 2011) | 10 lines
+
+ft2232_spi: fix arm-usb-ocd and arm-usb-ocd-h
+
+These devices have an additional output buffer which is activated only
+by pulling ADBUS4 low. This patch was real-life tested with
+arm-usb-ocd; arm-usb-ocd-h should be the same (as it shares the same
+documentation).
+
+Signed-off-by: Paul Fertser <fercerpav@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1477 | hailfinger | 2011-12-20 02:54:19 +0100 (Tue, 20 Dec 2011) | 12 lines
+
+Speed up dediprog SPI page writes
+
+All chips which use spi_chip_write_256 should be written at native
+speed. Chips using spi_chip_write_1 or spi_chip_write_aai will
+still be slow.
+
+Thanks to Steven A. Falco for testing with a ST/Numonyx M25P16.
+Thanks to David Hendricks for testing with a Winbond W25Q64.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Steven A. Falco <sfalco@coincident.com>
+
+------------------------------------------------------------------------
+r1476 | hailfinger | 2011-12-20 01:51:44 +0100 (Tue, 20 Dec 2011) | 20 lines
+
+Cross-compilation fixes
+
+Switch from host OS detection to target OS detection.
+Complain about unknown target OS/architecture.
+Disable annoying format string warnings on DJGPP.
+
+Native and cross-compilation now usually just require setting CC.
+Examples:
+make CC=i586-pc-msdosdjgpp-gcc
+make CC="clang -m64"
+make CC=i686-w64-mingw32-gcc
+
+Tested for a boatload of native and cross compilation configurations.
+
+There is a new target "make libpayload" in case you don't want to
+specify all tools by hand.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1475 | hailfinger | 2011-12-20 01:19:29 +0100 (Tue, 20 Dec 2011) | 26 lines
+
+Have all programmer init functions register bus masters/programmers
+
+All programmer types (Parallel, SPI, Opaque) now register themselves
+into a generic programmer list and probing is now programmer-centric
+instead of chip-centric.
+Registering multiple SPI/... masters at the same time is now possible
+without any problems. Handling multiple flash chips is still unchanged,
+but now we have the infrastructure to deal with "dual BIOS" and "one
+flash behind southbridge and one flash behind EC" sanely.
+
+A nice side effect is that this patch kills quite a few global variables
+and improves the situation for libflashrom.
+
+Hint for developers:
+struct {spi,par,opaque}_programmer now have a void *data pointer to
+store any additional programmer-specific data, e.g. hardware
+configuration info.
+
+Note:
+flashrom -f -c FOO -r forced_read.bin
+does not work anymore. We have to find an architecturally clean way to
+solve this.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1474 | hailfinger | 2011-12-18 16:01:24 +0100 (Sun, 18 Dec 2011) | 14 lines
+
+Add struct flashctx * parameter to all functions accessing flash chips.
+
+All programmer access function prototypes except init have been made
+static and moved to the respective file.
+
+A few internal functions in flash chip drivers had chipaddr parameters
+which are no longer needed.
+
+The lines touched by flashctx changes have been adjusted to 80 columns
+except in header files.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1473 | hailfinger | 2011-12-14 23:25:15 +0100 (Wed, 14 Dec 2011) | 20 lines
+
+Use struct flashctx instead of struct flashchip for flash chip access
+
+struct flashchip is used only for the flashchips array and for
+operations which do not access hardware, e.g. printing a list of
+supported flash chips.
+
+struct flashctx (flash context) contains all data available in
+struct flashchip, but it also contains runtime information like
+mapping addresses. struct flashctx is expected to grow additional
+members over time, a prime candidate being programmer info.
+struct flashctx contains all of struct flashchip with identical
+member layout, but struct flashctx has additional members at the end.
+
+The separation between struct flashchip/flashctx shrinks the memory
+requirement of the big flashchips array and allows future extension
+of flashctx without having to worry about bloat.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1472 | hailfinger | 2011-12-08 08:49:11 +0100 (Thu, 08 Dec 2011) | 8 lines
+
+Update URLs in print.c
+
+Move Asus A8Jm, Asus M6Ne to the laptop section.
+No working URL for the A8Jm found.
+
+Signed-off-by: Benjamin Bellec <b.bellec@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1471 | stefanct | 2011-12-02 22:48:17 +0100 (Fri, 02 Dec 2011) | 40 lines
+
+Add a bunch of new/tested stuff and various small changes 9
+
+Tested mainboards:
+OK:
+- ABIT NF-M2S
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008155.html
+- ASUS P5K-VM
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008172.html
+- ASUS M5A99X EVO
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008152.html
+- ASUS Z8PE-D12
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008195.html
+- PC Engines Alix.2d3
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008244.html
+NOT OK:
+- ASUS P8H61 PRO
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008308.html
+- ASUS P8P67 (rev. 3.1)
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008292.html
+- MSI MS-7613 (Iona-GL8E)
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008295.html
+- MSI MS-7635 (H55M-ED55)
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008167.html
+- Supermicro X9SCL
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008254.html
+- ZOTAC H67-ITX WiFi
+  http://paste.flashrom.org/view.php?id=902
+
+Tested flash chips:
+- mark Pm29F002T as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008171.html
+- mark AMIC A49LF040A as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008244.html
+- mark Winbond W39V040FC as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-November/008281.html
+
+- source format fixes
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1470 | stefanct | 2011-11-23 10:13:48 +0100 (Wed, 23 Nov 2011) | 7 lines
+
+Unsignify lengths and addresses in chip functions and structs
+
+Push those changes forward where needed to prevent new sign
+conversion warnings where possible.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1469 | stefanct | 2011-11-19 20:31:17 +0100 (Sat, 19 Nov 2011) | 6 lines
+
+Add board enable for ASUS A7N8X-VM/400
+
+http://www.flashrom.org/pipermail/flashrom/2011-November/008274.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1468 | stefanct | 2011-11-16 23:08:11 +0100 (Wed, 16 Nov 2011) | 11 lines
+
+Add board enable for ASRock ConRoeXFire-eSATA2
+
+The reverse engineering was done by Joshua. The actual patch was
+fabricated by Paul with some polishing by Stefan.
+
+Success log:
+http://www.flashrom.org/pipermail/flashrom/2011-November/008257.html
+
+Signed-off-by: Joshua Roys <roysjosh at gmail.com>
+Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1467 | stefanct | 2011-11-15 09:08:15 +0100 (Tue, 15 Nov 2011) | 14 lines
+
+Add board enable for ASUS P4GV-LA (Guppy)
+
+The reverse engineering was done by Joshua. The actual patch was
+fabricated by Stefan.
+
+Request:
+http://www.flashrom.org/pipermail/flashrom/2011-November/008241.html
+Success report:
+http://paste.flashrom.org/view.php?id=914
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Tested-by: Mugendai <mugendai42@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1466 | stefanct | 2011-11-14 14:00:12 +0100 (Mon, 14 Nov 2011) | 12 lines
+
+board_enable.c: Make it8712f_gpio_set generic
+
+This looks suspiciously like intel_ich_gpio_set.
+
+Based on that, add board enables for the ASUS P5N-D and P5N-E SLI.
+This was tested by Guillaume Poirier-Morency on a P5N-D:
+http://www.flashrom.org/pipermail/flashrom/2011-August/007706.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Small changes were also contributed and
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1465 | stefanct | 2011-11-14 00:03:30 +0100 (Mon, 14 Nov 2011) | 7 lines
+
+Create a directory for documentation files
+
+Move the serprog specification there and document a few things we could not
+figure out on intel platforms yet.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1464 | stefanct | 2011-11-13 16:17:10 +0100 (Sun, 13 Nov 2011) | 11 lines
+
+ichspi: fix ich_init_opcodes() calls in ich_init_spi()
+
+By calling it early ichspi_lock was not set up correctly in accordance
+with the corresponding register, hence ich_init_opcodes() was always
+trying to programming the opcodes instead of reading them in from the
+opmenu in case of a locked down configuration.
+
+Thanks to Jonathan A. Kollasch for reporting this bug.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1463 | hailfinger | 2011-11-10 00:40:00 +0100 (Thu, 10 Nov 2011) | 16 lines
+
+Register Parallel/LPC/FWH programmers the same way SPI programmers are registered.
+
+All programmers are now calling programmer registration functions and
+direct manipulations of buses_supported are not needed/possible anymore.
+
+Note: Programmers without parallel/LPC/FWH chip support should not call
+register_par_programmer().
+
+Additional fixes:
+Set max_rom_decode.parallel for drkaiser.
+Remove abuse of programmer_map_flash_region in it85spi.
+Annotate several FIXMEs in it85spi.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-By: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1462 | stefanct | 2011-11-08 12:55:24 +0100 (Tue, 08 Nov 2011) | 6 lines
+
+ichspi: print flash descriptor dependent information only when it is valid
+
+Also, fix some coding style issues.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1461 | stefanct | 2011-11-08 11:55:54 +0100 (Tue, 08 Nov 2011) | 30 lines
+
+ichspi: add support for Intel Hardware Sequencing
+
+Based on the new opaque programmer framework this patch adds support
+for Intel Hardware Sequencing on ICH8 and its successors.
+
+By default (or when setting the ich_spi_mode option to auto)
+the module tries to use swseq and only activates hwseq if need be:
+- if important opcodes are inaccessible due to lockdown
+- if more than one flash chip is attached.
+The other options (swseq, hwseq) select the respective mode (if possible).
+
+A general description of Hardware Sequencing can be found in this blog entry:
+http://blogs.coreboot.org/blog/2011/06/11/gsoc-2011-flashrom-part-1/
+
+Besides adding hwseq this patch also introduces these unrelated changes:
+
+- Fix enable_flash_ich_dc_spi to pass ERROR_FATAL from ich_init_spi.
+  The whole error handling looks a bit odd to me, so this patch does
+  change very little. Also, it does not touch the tunnelcreek method,
+  which should be refactored anyway.
+
+- Add null-pointer guards to find_opcode and find_preop
+  to matches the other opcode methods better:
+  curopcodes == NULL has some meaning and is actively used/checked in
+  other functions.
+
+TODO: adding real documentation when we have a directory for it
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1460 | stefanct | 2011-11-07 00:51:09 +0100 (Mon, 07 Nov 2011) | 27 lines
+
+ichspi: use a variable to distinguish ich generations instead of spi_programmer->type
+
+The type member is enough most of the time to derive the wanted
+information, but
+ - not always (e.g. ich_set_bbar),
+ - only available after registration, which we want to delay till the
+   end of init, and
+ - we really want to distinguish between chipset version-grained
+   attributes which are not reflected by the registered programmer.
+
+Hence this patch introduces a new static variable which is set up
+early by the init functions and allows us to get rid of all "switch
+(spi_programmer->type)" in ichspi.c. We reuse the enum introduced
+for descriptor mode for the type of the new variable.
+
+Previously magic numbers were passed by chipset_enable wrappers. Now
+they use the enumeration items too. To get this working the enum
+definition had to be moved to programmer.h.
+
+Another noteworthy detail: previously we have checked for a valid
+programmer/ich generation all over the place. I have removed those
+checks and added one single check in the init method. Calling any
+function of a programmer without executing the init method first, is
+undefined behavior.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1459 | hailfinger | 2011-11-04 22:35:26 +0100 (Fri, 04 Nov 2011) | 10 lines
+
+Add opaque programmer registration infrastructure
+
+An opaque programmer does not allow direct flash access and only offers
+abstract probe/read/erase/write methods.
+Due to that, opaque programmers need their own infrastructure and
+registration framework.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1458 | stefanct | 2011-11-02 15:31:18 +0100 (Wed, 02 Nov 2011) | 9 lines
+
+Add board enable for Sun Ultra 40 M2
+
+Failure report with logs:
+http://www.flashrom.org/pipermail/flashrom/2011-October/008158.html
+Success report:
+http://paste.flashrom.org/view.php?id=889
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1457 | stefanct | 2011-10-23 00:01:09 +0200 (Sun, 23 Oct 2011) | 58 lines
+
+Fix all ASUS P5GD* board enables
+
+Changes related to P5GD1 variants:
+- Reorder "P5GD1 Pro" in print.c and include a DMI patter to its board enable
+- Add an untested "P5GD1(-VM)" board enable and add an entry to print.c
+- Add P5GD1-VM/S variant as reported by "Limer"
+
+Changes related to P5GD(2/C) variants:
+- Fix the name of "P5GDC-V Deluxe" board enable and add a DMI pattern and
+  print.c entry. NB: there is no "P5GDC-V" board.
+- Add a generic match for P5GD(2/C)* boards with a not tested tag.
+  This are the potential targets for this according to the asus ftp:
+  ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/
+   Unsupported variants of the P5GD2:
+    P5GD2, P5GD2 Deluxe, P5GD2 Pro, P5GD2-X
+    (P5GD2 Premium is already tested)
+    (there seems to be also a P5GD2-TVM/GB/SI in the wild, which is not known to
+    asus :)
+   Unsupported variants of the P5GDC:
+   P5GDC Pro, P5GDC-MX
+    (P5GDC Deluxe and P5GDC-V Deluxe are already tested)
+
+ References:
+P5GD1 PRO (dmi "P5GD1 PRO")
+  smbus: 0x8086, 0x266a, 0x1043, 0x80a6; audio: 0x8086, 0x2668, 0x1043, *0x814e*
+  http://www.coreboot.org/pipermail/flashrom/2010-August/004539.html
+P5GD1 (dmi "P5GD1")
+  The non-pro version seems to match the pro pci pattern, but could be
+  distinguished by the SATA ID of 1043:2604 vs. 1043:2601:
+  https://launchpadlibrarian.net/62167576/Lspci.txt
+  or a DMI pattern of course.
+P5GD1-VM (dmi "P5GD1-VM")
+  This does also match the current PCI IDs.
+  https://bugs.launchpad.net/ubuntu/+source/linux/+bug/465379
+
+- P5GD2 Premium (dmi "P5GD2-Premium")
+  smbus: 0x8086, 0x266a, 0x1043, 0x80a6; audio: 0x8086, 0x2668, 0x1043, 0x813d
+  http://www.flashrom.org/pipermail/flashrom/2010-August/004555.html
+- P5GDC-V Deluxe (dmi "P5GDC-V")
+  smbus: 0x8086, 0x266a, 0x1043, 0x80a6; audio: 0x8086, 0x2668, 0x1043, 0x813d
+  http://www.flashrom.org/pipermail/flashrom/2010-September/004939.html
+- P5GDC Deluxe (dmi "P5GDC")
+  smbus: 0x8086, 0x266a, 0x1043, 0x80a6; audio: 0x8086, 0x2668, 0x1043, 0x813d
+  http://www.flashrom.org/pipermail/flashrom/2010-September/004684.html
+
+- P5GDC Pro, P5GDC-MX, P5GD2-X, P5GD2 Pro, P5GD2
+  no useful logs found
+- P5GD2-Deluxe (dmi "P5GD2-Deluxe")
+  smbus: 0x8086, 0x266a, 0x1043, 0x80a6; audio: 0x8086, 0x2668, 0x1043, 0x813d
+  https://bugs.launchpad.net/ubuntu/+source/foomatic-filters/+bug/572514
+
+- P5GD2-TVM/GB/SI (dmi "P5GD2-TVM/GB/SI")
+  smbus: 0x8086, 0x266a, 0x1043, 0x266a; audio: 0x8086, 0x2668, 0x1043, *0x81a7*
+  https://bugs.launchpad.net/ubuntu/+source/linux/+bug/462500
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+and due to the tremendous interest... ;)
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1456 | stefanct | 2011-10-22 23:45:27 +0200 (Sat, 22 Oct 2011) | 8 lines
+
+serprog: small improvements
+
+- rename serprog_delay parameter to usecs
+- fix code style, (output) formatting issues and comments
+- sp_docommand: remove unnecessary malloc+memcpy and fix formatting
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1455 | stefanct | 2011-10-21 15:20:11 +0200 (Fri, 21 Oct 2011) | 13 lines
+
+Add board enable for ABIT AV8
+
+I disassembled the write enable and the write disable functions from
+the Award BIOS image and reconstructed C code to understand for
+myself what happens. For details see:
+http://www.flashrom.org/pipermail/flashrom/2011-October/008033.html
+
+I compared the download pages of both, abit AV8 and abit AV8-3rd Eye,
+and the BIOS downloads are the same. So it's save to assume that this
+board enable works on both versions. Tested on AV8.
+
+Signed-off-by: Christoph Grenz <christophg+cb@grenz-bonn.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1454 | stefanct | 2011-10-21 14:33:07 +0200 (Fri, 21 Oct 2011) | 87 lines
+
+Add a bunch of new/tested stuff and various small changes 8
+
+Tested mainboards:
+OK:
+- ASUS Crosshair II Formula
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007888.html
+- ASUS K8N
+  http://paste.flashrom.org/view.php?id=856
+- ASUS M2N-E SLI
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007909.html
+- ASUS M3N78-VM
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006496.html
+- ASUS M4A78LT-M LE
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007869.html
+- ASUS M4A89GTD PRO
+  http://www.flashrom.org/pipermail/flashrom/2011-February/005824.html
+- MSI A75MA-G55 (MS-7696)
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008055.html
+- PCCHIPS M598LMR (V9.0)
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008051.html
+- ECS P4VXMS (V1.0A)
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007986.html
+- Foxconn P4M800P7MA-RS2
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008114.html
+- GIGABYTE GA-P67A-UD3P
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007930.html
+- GIGABYTE Z68MX-UD2H-B
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008080.html
+- ZOTAC Fusion-ITX WiFi (FUSION350-A-E)
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008011.html
+NOT OK:
+- ASUS P8B-E/4L
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008047.html
+- ASUS P8B WS
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008081.html
+
+Tested chipsets:
+- MCP78S (:075d)
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007612.html
+- VT8233 (:3074)
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007986.html
+- SiS 530 (:0530)
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008051.html
+- P67 (:1c46)
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007930.html
+ - Z68 (:1c44)
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008080.html
+
+Tested flash chips:
+- mark AMIC A29002T as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008085.html
+- mark Eon EN29F002(A)(N)T as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008053.html
+- mark EonEN25F16 as  TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-February/005824.html
+- mark Macronix MX29F002(N)T as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008083.html
+- mark Pm39LV040 as TEST_OK_PR
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007942.html
+- mark Pm39LV010 as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007942.html
+- mark SST49LF008A as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007989.html
+- mark SyncMOS {F,S,V}29C51002T as TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008052.html
+- mark W39V040B as write tested
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008114.html
+- mark W39V040C as  TEST_OK_PREW
+  http://www.flashrom.org/pipermail/flashrom/2011-October/008114.html
+
+- remove superfluous line break in enable_flash_ich_dc_spi
+- m->M in "min" and "max" (voltage) in print_wiki.c
+
+- spi25: get rid of unneccessary line breaks (on failed probes)
+which is
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+- rayer_spi.c: Remove double word: `s/the the/the/`
+which is
+Signed-off-by: Paul Menzel <paulepanter@users.sourceforge.net>
+
+The parts added until 2011-10-14 (most of this patch) were
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+everything else is
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1453 | uwe | 2011-10-21 01:14:10 +0200 (Fri, 21 Oct 2011) | 33 lines
+
+Add support for the GOEPEL PicoTAP programmer.
+
+http://www.goepel.com/en/jtagboundary-scan/hardware/picotap.html
+
+This device is actually a JTAG adapter, but since it uses standard
+FT2232 A interface pins, it can be easily used as SPI programmer
+(tested it here successfully). PicoTAP supports only 5V output, so one
+needs to reduce this to 3.3V in a same manner as DLP Design DLP-USB1232H, see
+
+  http://flashrom.org/FT2232SPI_Programmer#DLP_Design_DLP-USB1232H
+
+for details.
+
+The PicoTAP pin-out is as follows:
+
+  PicoTAP |  SPI
+ ---------+-------
+    TCK   | SCLK
+    TMS   |  CS#
+    TDI   |  SO
+    TDO   |  SI
+   /TRST  |  -
+    GND   |  GND
+    +5V   |  VCC, HOLD# & WP# after 3.3V regulator
+
+I managed to run PicoTAP in 10MHz, 15MHz and 30MHz modes (by forcing
+DIVIDE_BY), against SST25VF016B SPI flash, read/write/erase all worked
+fine (write seems somewhat slow).
+
+Signed-off-by: Samir Ibrad?\197?\190i?\196?\135 <sibradzic@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1452 | stefanct | 2011-10-20 14:57:14 +0200 (Thu, 20 Oct 2011) | 7 lines
+
+ichspi: add (partially) dead support code for Intel Hardware Sequencing
+
+This was done to ease the review. Another patch will hook up (and
+explain) this code later.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1451 | uwe | 2011-10-14 22:33:14 +0200 (Fri, 14 Oct 2011) | 28 lines
+
+TIAO/DIYGADGET USB Multi-Protocol Adapter (TUMPA) support.
+
+Thanks to TIAO/DIYGADGET for sponsoring a test device!
+
+This is an FTDI FT2232H based device which provides an easily accessible JTAG,
+SPI, I2C, serial breakout. The SPI part can be used to flash SPI flash chips
+using flashrom.
+
+http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html
+http://www.tiaowiki.com/w/TIAO_USB_Multi_Protocol_Adapter_User%27s_Manual#SPI_Connector_1
+
+There are two SPI connectors (pin headers) on the board: SPI1, which is
+connected to the FT2232H's A interface, and SPI2, which is connected to the
+chip's B interface. Both can be used to flash SPI chips:
+
+ flashrom -p ft2232_spi:type=tumpa,port=A
+ flashrom -p ft2232_spi:type=tumpa,port=B
+
+The default interface is A, so for SPI1 you can also just write:
+
+ flashrom -p ft2232_spi:type=tumpa
+
+I tested all operations on both interfaces, everything works fine.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+
+------------------------------------------------------------------------
+r1450 | stefanct | 2011-09-19 00:42:18 +0200 (Mon, 19 Sep 2011) | 17 lines
+
+Revert "Unsignify lengths and addresses in chip functions and structs"
+
+- probe_timing was changed to unsigned although we use negative values
+  for special cases
+- some code was not changed along hence did no longer compile:
+  * dediprog's read and write functions
+  * linux_spi's read and write functions
+- it introduced a number of new sign conversion warnings
+  (http://paste.flashrom.org/view.php?id=832)
+
+To be safe this patch reverts all changes made in r1448, a corrected
+patch will follow later.
+
+Thanks to idwer for pointing out the problem first!
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1449 | stefanct | 2011-09-18 17:15:31 +0200 (Sun, 18 Sep 2011) | 11 lines
+
+ichspi: inform the user about the consequences of the security override strap
+
+Ibex Peak SPI Programming Guide:
+The PCH has a mechanism to set up to 5 address ranges from HOST access. These are
+defined in PR0, PR1, PR2, PR3 and PR4 in the PCH EDS. These address ranges are NOT
+unlocked by assertion of Flash descriptor Override.
+
+Also, the datasheets mention the bit in their description of FRAP but not PR[N].
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1448 | stefanct | 2011-09-18 02:41:33 +0200 (Sun, 18 Sep 2011) | 4 lines
+
+Unsignify lengths and addresses in chip functions and structs
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1447 | stefanct | 2011-09-18 00:21:55 +0200 (Sun, 18 Sep 2011) | 8 lines
+
+ichspi: unlock PR register restrictions on ICH8+ if not locked down
+
+Tested-by: Shailendra Sodhi
+(predecessor/proof of concept patch)
+http://www.flashrom.org/pipermail/flashrom/2011-August/007717.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1446 | stefanct | 2011-09-17 23:21:48 +0200 (Sat, 17 Sep 2011) | 4 lines
+
+ichspi: add prettyprinting for PR registers on ICH8+
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1445 | stefanct | 2011-09-17 23:21:42 +0200 (Sat, 17 Sep 2011) | 10 lines
+
+ichspi: don't touch the nonexistent(?) BBAR register on ICH8
+
+There is no sign of BBAR (BIOS Base Address Configuration Register)
+in the public datasheet (or specification update) of the ICH8. Also,
+the offset of that register has changed between ICH7 (SPIBAR + 50h)
+and ICH9 (SPIBAR + A0h), so we have no clue if or where it is on
+ICH8. Better don't try to touch it at all and assume/hope it is 0.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1444 | stefanct | 2011-09-17 21:53:11 +0200 (Sat, 17 Sep 2011) | 6 lines
+
+ichspi: improve prettyprint_opcodes
+
+add headers for the columns and some decoding into human readable format.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1443 | stefanct | 2011-09-16 01:52:55 +0200 (Fri, 16 Sep 2011) | 43 lines
+
+ichspi: add ICH/PCH flash descriptor decoding via FDOC/FDOD
+
+based on the work of Matthias 'mazzoo' Wenzel this patch adds pretty
+printing of those ICH/PCH flash descriptor sections that are
+cached/mapped by the chipset (and which are therefore reachable via
+FDOC/FDOD registers).
+
+this includes the following:
+- content section:
+    describes the image and some generic properties (number of
+    sections, offset of sections, PCH/ICH and MCH/PROC strap
+    offsets and lengths)
+- component section:
+    identify the different SPI flash chips and their capabilities.
+- region section
+    similarly to a partition table this describes the different regions.
+    the content of FLREG* is derived from this section.
+- master section
+    defines SPI master (host, ME, GbE) access rights of the
+    individual regions. the content of PR* is derived from this section.
+
+this is only a part of the data included in the descriptor. other
+information can be retrieved from a complete binary dump of the
+descriptor region only.
+
+this patch also adds macros and pretty printing for "Vendor Specific
+Component Capabilities" registers: there are two of them: lower and
+upper. they describe the properties of the address space divided by
+FPBA (which allows to use multiple flash chips or partitions with
+different properties). the properties of all supported flash chips
+(together with their RDIDs) are stored in the same format in table
+in a descriptor section (which is used by the ME apparently). a
+later patch will use the macros outside of ichspi.c which is the
+reason why the prettyprinting function and the register bit macros
+are not defined in ichspi.c but ich_descriptors.h (else they would
+be moved in the follow-up patch).
+
+because this patch relies on (compiler) implementation-specific
+layouting of bit-fields, it checks for correct layout before taking
+any action on runtime.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1442 | stefanct | 2011-09-16 01:38:14 +0200 (Fri, 16 Sep 2011) | 9 lines
+
+serprog: add SPI support
+
+Adds a new opcode (0x13) that just relays SPI bytes and wires it up to be
+usable within serprog.c. Checks for mandatory opcodes are moved around and
+changed a bit, but non-SPI programmers should not be harmed by this patch.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1441 | stefanct | 2011-09-15 00:09:48 +0200 (Thu, 15 Sep 2011) | 8 lines
+
+Add printing of chip voltage ranges to print_wiki.c
+
+- add voltage ranges
+- center some headers (test values OK, No, ? are centered via wiki templates)
+- fix style error in header (align:right -> text-align:right)
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1440 | stefanct | 2011-09-14 01:14:25 +0200 (Wed, 14 Sep 2011) | 9 lines
+
+Make the laptop warning less scary if unsure
+
+Telling the user to use "force_I_want_a_brick" if it is not even a
+laptop, is a bit over-the-top. Introduce a new laptop parameter
+"this_is_not_a_laptop" that allows to force operation, but only if
+the detection is not sure.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1439 | uwe | 2011-09-14 00:05:44 +0200 (Wed, 14 Sep 2011) | 10 lines
+
+Add probe/read support for the Catalyst CAT28F512 chip.
+
+Write and erase are NOT yet supported!
+
+Probe and read are tested by Andrew Morgan and Uwe Hermann on Intel NICs.
+
+Signed-off-by: Andrew Morgan <ziltro@ziltro.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1438 | stefanct | 2011-09-13 00:55:01 +0200 (Tue, 13 Sep 2011) | 17 lines
+
+Reformat -L output and add printing of chip voltage ranges to print.c
+
+besides adding output for the voltage ranges, this patch also changes
+various aspects of the -L output:
+- sizes are right aligned now with a fixed length of 5
+- space between columns is selectable with a constant
+- test results are always shown in the same column ("PR" and " R"
+  instead of "PR" and "R ")
+- vendor and device names are split on a delimiter (currently '/') and
+  spread over mutliple lines but only if the tokens are not too short.
+  all other columns are printed on the first line of a chip.
+- voltage ranges are printed in verbose mode only
+
+it also gets rid of POS_PRINT and digits
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1437 | hailfinger | 2011-09-12 08:17:06 +0200 (Mon, 12 Sep 2011) | 9 lines
+
+Add support for Xilinx parallel III (DLC5) programing cable
+
+The rayer_spi driver defaults to the RayeR cable, but selecting other
+predefined pin layouts with the type= parameter is possible:
+flashrom -p rayer_spi:type=xilinx
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1436 | stefanct | 2011-09-12 00:08:58 +0200 (Mon, 12 Sep 2011) | 10 lines
+
+Print out the flash chip found after the probing loop in verbose mode
+
+This allows easier identification of the flash chip used in verbose logs.
+There is no (additional) output if
+* -c is used to specify a flash chip, or
+* multiple chips are detected, or
+* no chips are detected.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1435 | stefanct | 2011-09-09 14:46:32 +0200 (Fri, 09 Sep 2011) | 8 lines
+
+Revamp the warning of failing to set BIOS write enable in enable_flash_ich
+
+ - introduce a new variable 'wanted' that is used instead of 'new'
+ - use 'new' for the actual value contained in BIOS_CNTL after we tried to write it
+ - rephrase the warning which now also includes the old and new values besides the wanted one
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1434 | uwe | 2011-09-08 21:55:18 +0200 (Thu, 08 Sep 2011) | 11 lines
+
+Add initial Atmel AT49LH002 FWH/LPC chip support.
+
+The chip code is untested, only one erase function out of two is currently
+implemented, and unlocking/printlocking is not yet supported.
+
+Thanks Mattias Mattsson <vitplister@gmail.com> for the initial patch!
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1433 | hailfinger | 2011-09-08 02:00:29 +0200 (Thu, 08 Sep 2011) | 12 lines
+
+Change programmer selection in cli and generic code
+
+Bugfix: Do not accept multiple conflicting --programmer selections.
+Restriction: Do not accept multiple --programmer selections even if
+  there is no conflict.
+Unexport the programmer variable.
+programmer_init requires the programmer as first parameter.
+The default programmer selection is now part of cli_classic.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1432 | uwe | 2011-09-07 22:48:34 +0200 (Wed, 07 Sep 2011) | 6 lines
+
+Small fixes for the linux_spi programmer code.
+
+Signed-off-by: Sven Schnelle <svens@stackframe.org>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1431 | uwe | 2011-09-07 22:20:25 +0200 (Wed, 07 Sep 2011) | 12 lines
+
+Mark the GIGABYTE GA-8I945GZME-RH and SST SST25LF040A as supported.
+
+Success report:
+http://www.flashrom.org/pipermail/flashrom/2011-June/006797.html
+
+lspci and other info:
+http://www.flashrom.org/pipermail/flashrom/2010-August/004531.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1430 | uwe | 2011-09-07 21:18:25 +0200 (Wed, 07 Sep 2011) | 19 lines
+
+Add Intel Tunnel Creek chipset support, mark it as tested.
+
+Intel's Tunnel Creek chipset supports both an SPI and an LPC bus. Set the
+chipset table entry for Tunnel Creek to the new function
+enable_flash_tunnelcreek(), which will read the hardware straps and return
+support for the bus that has been used for booting. This function uses
+ich_init_spi() with ich_generation set to 7 for initializing the SPI bus
+if necessary.
+
+SPI functionality tested on actual hardware, Tunnel Creek LPC interface not
+tested yet (missing hardware for that).
+
+Log file / success report:
+http://www.flashrom.org/pipermail/flashrom/2011-September/007823.html
+
+Signed-off-by: Ingo Feldschmid <ifel@msc-ge.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1429 | uwe | 2011-09-06 20:49:31 +0200 (Tue, 06 Sep 2011) | 6 lines
+
+Kill all exit() calls in chipset_enable.c.
+
+Signed-off-by: Tadas Slotkus <devtadas@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1428 | uwe | 2011-09-06 20:17:02 +0200 (Tue, 06 Sep 2011) | 6 lines
+
+Fix linux_spi.c build on 32bit systems.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1427 | uwe | 2011-09-03 20:37:52 +0200 (Sat, 03 Sep 2011) | 21 lines
+
+Add support for the Linux SPI subsystem (spidev).
+
+See http://www.kernel.org/doc/Documentation/spi/spidev for an introduction.
+
+Usage is as follows:
+
+  flashrom -p linux_spi:dev=/dev/spidevX.Y
+
+where X is the bus number, and Y device. It accepts an optional parameter
+'speed' which allows to set the SPI clock speed in kHz.
+
+Tested on an Atmel AVR32AP7000 board (NGW100 Network Gateway Kit), see
+below, which was used to program a ThinkPad X60, but it should work on every
+other Linux system, too.
+  
+  http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4102)
+
+Signed-off-by: Sven Schnelle <svens@stackframe.org>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1426 | uwe | 2011-09-03 19:15:00 +0200 (Sat, 03 Sep 2011) | 6 lines
+
+Introduce ERROR_FATAL, abort upon failed chipset enables.
+
+Signed-off-by: Tadas Slotkus <devtadas@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1425 | stefanct | 2011-09-03 13:22:27 +0200 (Sat, 03 Sep 2011) | 92 lines
+
+Add a bunch of new/tested stuff and various small changes 7
+
+- add Asus Crosshair IV Extreme to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007640.html
+- add Biostar N68S3+ to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007788.html
+- add P7H55-M LX to the list of supported boards
+  although flashrom works correctly, it is marked as not ok, because flashing the
+  vendor image will break the LAN interface.
+- add GA-X58A-UD7 to the list of supported boards
+  http://paste.flashrom.org/view.php?id=739
+- add Asus P4P800-VM to print.c
+  (has a working board enable)
+- add Asus K8V-X to print.c
+  reported by florz
+  http://paste.flashrom.org/view.php?id=742
+- add Intel D865GLC to print.c as non-working (ICH5 with BIOS lock enable)
+  reported by jmd on IRC
+  http://paste.flashrom.org/view.php?id=775
+- add Intel DH67CF to print.c as non-working (H67 with BIOS lock enable and locked ME region)
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007789.html
+- add ECS P4M800PRO-M (V1.0A) to the list of supported boards
+  reported by dweg on IRC (hot flashed a SST49LF040B, original was W39V040B)
+- add X8DTU-6TF+ to print.c (needs ME unlocking)
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007553.html
+- add Shuttle FH67 (used in the SH67H3 barebone) to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007749.html
+- add Tyan S2912 to the list of supported boards
+  reported by erlan on IRC
+- add ZOTAC GeForce 8200 to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007612.html
+
+- mark AT25DF321A as TEST_OK_PROBE
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007553.html
+- mark 28F001BN/BX-T as TEST_OK_PR
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007208.html
+- rename MX29F002
+  http://patchwork.coreboot.org/patch/2794/
+- mark SST39SF040 as fully tested
+  reported by Florian 'florz' Zumbiehl
+  http://paste.flashrom.org/view.php?id=742
+- mark SST49LF040B as fully tested
+  reported by dweg on IRC and later by Armin on the ml:
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007764.html
+
+- mark H55 chipset as OK
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007432.html
+- mark H67 chipset as OK
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007749.html
+- mark a MCP61 version as OK
+  http://www.flashrom.org/pipermail/flashrom/2011-September/007788.html
+- add preliminary X79 (patsburg) PCI IDs
+  0x1d40 was reported already as working (not archived in our pipermail?)
+  http://marc.info/?l=flashrom&m=130683026218257&w=2
+
+- mark "82557/8/9/0/1 Ethernet Pro 100" in nicintel.c as working
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007480.html
+
+- rename some chips that had gratuitous "probing" suffixes:
+  - SST25VF010.REMS
+  - SST25VF040.REMS
+  - M25P05.RES
+  - M25P10.RES
+  some other chip names with suffixes are needed due to lack of support
+  for multiple probe functions per chip. this is explained here:
+  http://www.flashrom.org/pipermail/flashrom/2011-August/007597.html
+
+- remove unneeded nicintel_spi-related function declarations in programmer.h
+
+- typos and whitespace fixes
+
+- fix Asus P4P800-E Deluxe detection
+  The original board enable was added before DMI matching and used
+  the IDs of a Promise controller as secondary PCI ID set. The
+  controller could be disabled in the BIOS which would make the
+  board not match. This patch uses the SMBus controller instead and
+  adds a DMI pattern. This was
+Tested-by: Michael Schneider <vdrportal_midas at gmx dot de>
+
+- add "Sealed-case PC" to the list of chassis type (as indicating "not a laptop")
+This is
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+the fix for the typo unusued -> unused is
+Signed-off-by: Sylvain "ythier" Hitier <sylvain.hitier@gmail.com>
+
+everything else is
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+And everything was reviewed and
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1424 | hailfinger | 2011-08-31 18:19:50 +0200 (Wed, 31 Aug 2011) | 5 lines
+
+Shorten some board enable related function names
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1423 | stefanct | 2011-08-27 23:19:56 +0200 (Sat, 27 Aug 2011) | 26 lines
+
+Fix printing of the Boot BIOS Straps on Intel chipsets
+
+The meaning of the bits involved has changed several times in the past.
+This patch takes these changes into account and hence fixes the output of the
+pretty printing of GCS on all SPI-supported Intel chipsets that are not ICH7 or
+NM10 (the latter were unaffected, because the defaults were correct).
+
+This patch also allows to differentiate Ibex Peak and Cougar Point chipsets from
+the earlier chipset series (ICH10) by adding new wrapper functions that set
+"ich_generation" to 11 and 12 respectively. This should not change behavior
+outside of enable_flash_ich_dc_spi, because the code path for
+ich_generation >=9 is equal.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+---
+defining all those arrays is not very elegant, but i think it is at least very
+readable this way. improvements are welcome!
+reviewers should have an eye on the codepaths for ich_generation >= 9. i did not
+spot a problem, but it should be checked again.
+
+alternatively we could just remove the pretty printing of GCS and just output
+the bits involved. i would like to keep the pch differentiation anyway though,
+because i feel it will become handy in the future.
+
+tested on my QS57-based thinkpad (probe + partial read)
+------------------------------------------------------------------------
+r1422 | uwe | 2011-08-26 23:11:41 +0200 (Fri, 26 Aug 2011) | 9 lines
+
+Add AMD Hudson chipset-enable.
+
+AMD Hudson has different vendor/device IDs than AMD SBx00, handle
+that properly.
+
+Signed-off-by: Wang Qing Pei <wangqingpei@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1421 | uwe | 2011-08-26 00:54:23 +0200 (Fri, 26 Aug 2011) | 9 lines
+
+Mark the AMD Am29LV008BB chip as fully tested.
+
+Thanks Mattias Mattsson <vitplister@gmail.com> for the report.
+http://www.flashrom.org/pipermail/flashrom/2011-July/007423.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1420 | uwe | 2011-08-26 00:44:11 +0200 (Fri, 26 Aug 2011) | 9 lines
+
+Add support for the Sharp LH28F008BJT-BTLZ1 chip.
+
+Tested by Mattias Mattsson <vitplister@gmail.com> on a PowerPC box.
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1419 | stefanct | 2011-08-25 16:06:50 +0200 (Thu, 25 Aug 2011) | 15 lines
+
+Add board enable for ASUS P5LP-LE
+
+Based on the REing of Michael Karcher and a good guess of Idwer Vollering.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Tested-by: Leon Zhang <leoncamel at gmail.com>
+http://www.coreboot.org/pipermail/flashrom/2010-August/004500.html
+Tested-by: medhi <nefkongo@hotmail.com>
+http://paste.flashrom.org/view.php?id=779
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+---
+i have added the DMI match and changed the board enable and wiki comments
+a bit. i am not sure if this is the right way to add it, because there are so many
+variations, but we can change that later too.
+------------------------------------------------------------------------
+r1418 | uwe | 2011-08-20 16:16:00 +0200 (Sat, 20 Aug 2011) | 23 lines
+
+Makefile: Fix MinGW build, improve output with bogus CC.
+
+As per IRC discussion, the "ARCH :=" line should be moved after any
+lines which set CC, as it uses CC itself. This fixes the MinGW build.
+
+Also, add a "2>/dev/null" in the "ARCH :=" as per suggestion from
+Stefan Tauner to improve the output in the case CC is bogus:
+
+Before:
+$ make CC=foo
+/bin/sh: foo: not found
+Checking for a C compiler... not found.
+make: *** [compiler] Error 1
+
+After:
+$ make CC=foo
+Checking for a C compiler... not found.
+make: *** [compiler] Error 1
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+
+------------------------------------------------------------------------
+r1417 | uwe | 2011-08-20 16:14:22 +0200 (Sat, 20 Aug 2011) | 14 lines
+
+Move the main() function from flashrom.c to cli_classic.c.
+
+The file flashrom.c is part of libflashrom and should thus not contain a
+main() function, that would break compilation of all frontends using
+libflashrom. Also, cli_classic.c is the right place anyway, as it's the
+main() of the CLI tool.
+
+Rename the simple wrapper cli_classic() in cli_classic.c to main(), as
+it's not really needed.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+
+------------------------------------------------------------------------
+r1416 | stefanct | 2011-08-18 04:27:19 +0200 (Thu, 18 Aug 2011) | 35 lines
+
+Makefile: fix and simplify test program compilations
+
+this was totally broken due to the make's shell function's temporal
+behavior.
+
+quote from the gnu make documentation
+(http://www.gnu.org/s/hello/manual/make/Shell-Function.html):
+"The commands run by calls to the shell function are run when the
+function calls are expanded"
+we have used the shell function to echo the test programs to a file.
+the file name used was equal for all tests and was overwritten for
+each test. the result was that all tests (in a single target?) used
+the last test program because the echoing of the test programs was
+done before all test compilations(!)
+see my mail for details:
+http://lists.gnu.org/archive/html/bug-make/2011-08/msg00010.html
+
+also the branching for testing ifeq ($(CONFIG_FT2232_SPI), yes) was
+unnecessarily complicated.
+
+in my approach here i am using verbatim variables (allows to define
+even complex test programs in the makefile without jumping through
+hoops) that get exported to environment variables (via "export",
+reference afterwards with "$$<varname>").
+
+i have also added the missing redirection of stderr to the compiler
+test and changed the definition of ARCH to use simple expansion (:=).
+
+the latter is still wrong, because it uses $(CC) before we check if
+a compiler is installed... makes the compiler check pretty much
+useless. The simple expansion just reduces the number of errors
+printed to 1.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1415 | stefanct | 2011-08-17 11:50:11 +0200 (Wed, 17 Aug 2011) | 10 lines
+
+Add support for the SST25LF080A flash chip
+
+Based on the definition of SST25LF040A and the public datasheet
+available here: http://www.sst.com/dotAsset/40316.pdf
+
+Also, move the SST25LF040A up to keep the list ordered
+alphabetically (while removing the ".RES" suffix).
+
+Signed-off-by: Zeus Castro <thezeusjuice@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1414 | stefanct | 2011-08-16 14:08:22 +0200 (Tue, 16 Aug 2011) | 19 lines
+
+Remove unneeded inclusions of chipdrivers.h
+
+this is related to the spi split patch as discussed in:
+http://www.flashrom.org/pipermail/flashrom/2010-February/thread.html#2364
+the old commit (r914) log notes:
+"Some of the spi programmer drivers required chipdrivers.h, needs fixing later: it87spi.c
+  ichspi.c   sb600spi.c   wbsio_spi.c   buspirate_spi.c   ft2232spi.c   bitbang_spi.c   dediprog.c"
+
+there still remain a few cases where chipdrivers.h is needed:
+dediprog.c (spi_read_chunked and spi_write_chunked)
+it87spi.c (due to spi_write_enable and spi_read_status_register)
+wbsio_spi.c (spi_programmer registration only)
+
+besides that, there are also non-spi files that do not need it.
+also, add flash.h to chipdrivers.h because it uses some types of it
+and remove flashchips.h from print.c
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1413 | hailfinger | 2011-08-15 21:54:20 +0200 (Mon, 15 Aug 2011) | 11 lines
+
+Fixup of r1397:
+- Mixing uninitialized and initialized local variables leads to
+  confusion.
+- ft2232_spi error cases should have gotten some error handling, and
+  that's the reason the curly braces were there.
+- Fixing typos/wording in some places would have been nice given that
+  those places were touched anyway.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1412 | stefanct | 2011-08-12 03:19:32 +0200 (Fri, 12 Aug 2011) | 13 lines
+
+ft2232_spi: add support for the Dangerous Prototypes Bus Blaster
+
+Add support for the Dangerous Prototypes Bus Blaster (v1/v2).
+The new model is called "busblaster".
+So far only v2 has been tested, but since both v1 and v2
+emulate a Amontec JTAGKEY in the default configuration,
+it is assumed that v1 should work fine as well.
+
+Information about the Busblaster can be found at:
+http://dangerousprototypes.com/docs/Bus_Blaster
+
+Signed-off-by: Steve Markgraf <steve@steve-m.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1411 | stefanct | 2011-08-11 07:47:32 +0200 (Thu, 11 Aug 2011) | 19 lines
+
+Add board enable for ASUS P5GD2 Premium
+
+This is based on Joshua's patch, but with a DMI pattern, contrary to
+http://www.flashrom.org/pipermail/flashrom/2010-September/004745.html
+Rationale: although it looks like all P5GD2/C* might use the same
+board enable (intel_ich_gpio21_raise), we need to add the variants
+individually as long as we don't have enough reports to make a
+better guess. This also guarantees correct output of flashrom -L and -z
+and on activation of the board enable - not like this:
+http://www.flashrom.org/pipermail/flashrom/attachments/20100930/2286e5d1/attachment-0003.txt
+
+Success report:
+http://www.flashrom.org/pipermail/flashrom/2010-August/004555.html
+
+Also, fix last commit by adding a missing comma.
+
+Tested-by: Roberto Malinverni
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1410 | stefanct | 2011-08-11 06:21:34 +0200 (Thu, 11 Aug 2011) | 15 lines
+
+Add (untested) board enable for Asus P5LD2
+
+There are numerous other variants of the P5LD2 which vary wildly not only in
+PCB layout but also in northbridges used, number of PCI, PCI-E and DIMM slots
+etc. This one is for the plain P5LD2 without any suffixes.
+
+This patch is essentially a rebased version of Joshua's patch, which was never
+tested (user did not reply). I have added additional PCI IDs and the DMI pattern
+and also changed the status to NT. An entry in the print.c table was also added.
+
+http://www.flashrom.org/pipermail/flashrom/2010-October/005080.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1409 | stefanct | 2011-08-09 03:49:34 +0200 (Tue, 09 Aug 2011) | 9 lines
+
+ichspi.c: refactor filling and reading the fdata/spid registers
+
+- add ich_fill_data to fill the chipset registers from an array
+- add ich_read_data to copy the data from the chipset register into an array
+- replace the existing code with calls to those functions
+- minor cosmetic changes
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1408 | stefanct | 2011-08-07 15:17:20 +0200 (Sun, 07 Aug 2011) | 8 lines
+
+Add a board enable for ASUS A8M2N-LA (HP OEM "NodusM3-GL8E")
+
+It is based on Joshua Roys' RE.
+http://www.flashrom.org/pipermail/flashrom/2011-August/007504.html
+
+Tested-by: M?\195?\161rton Mikl?\195?\179s
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1407 | stefanct | 2011-08-06 18:16:45 +0200 (Sat, 06 Aug 2011) | 19 lines
+
+Fix the A8N-SLI Deluxe board enable
+
+Long story short:
+- the A8N in print.c should be A8N-SLI Deluxe as documented
+- the A8N-SLI Deluxe board enable needs a DMI pattern, else it will get executed
+  on the A8N-SLI Premium unnecessarily.
+  http://www.flashrom.org/pipermail/flashrom/2010-August/004310.html
+  the DMI string is taken from an ubuntu bug report (a real dmidecode or flashrom
+  output was not found).
+  https://bugs.launchpad.net/ubuntu/+source/linux/+bug/807980
+- the other A8N-SLI variants seem to work without the board enable
+  A8N-SLI Premium:
+  http://www.flashrom.org/pipermail/flashrom/2010-August/004310.html
+  A8N-SLI:
+  http://www.coreboot.org/pipermail/coreboot/2009-June/049107.html
+  http://www.coreboot.org/pipermail/coreboot/2009-May/049002.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1406 | stefanct | 2011-08-06 18:16:33 +0200 (Sat, 06 Aug 2011) | 13 lines
+
+Fix the EP-8NPA7I (for the last time hopefully)
+
+ - retag it as OK (tested by Jonathan Kollasch when he wrote it)
+   http://patchwork.coreboot.org/patch/2106/
+ - add a line with identical pci ids but a different dmi pattern, so that EP-9NPA7I
+   is also matched. combining multiple boards in one line is problematic due to
+   print.c's detection of board enables - so dont bother for now.
+   http://www.flashrom.org/pipermail/flashrom/2011-June/006878.html
+
+See previous commit for additional information.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1405 | stefanct | 2011-08-06 14:45:21 +0200 (Sat, 06 Aug 2011) | 20 lines
+
+Clear byte 0x92 of the LPC bridge for all CK804 (and MCP51) chipsets
+
+The OEM BIOS on the EPoX EP-8PA7I and a number of other boards clear
+byte 0x92 in the LPC bridge configuration space.  Do the same for
+all CK804 chips, assuming this to be some sort of chipset-generic
+write-enable.
+
+Currently the same chipset enable is used for MCP51 (nForce 430).
+There have been reports of successful writes with its variations
+(e.g. A8N-LA (Nagami-GL8E)), but they were not tagged as OK. Due to
+the new "unsupported chipset"-message we will get success reports in
+the case this patch does not break anything on the MCP51-based boards.
+
+See also:
+http://www.flashrom.org/pipermail/flashrom/2011-July/007252.html
+http://patchwork.coreboot.org/patch/3176/
+
+Signed-off-by: Jonathan Kollasch <jakllsch@kollasch.net>
+Acked-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1404 | stefanct | 2011-08-04 19:40:25 +0200 (Thu, 04 Aug 2011) | 4 lines
+
+Introduce msg_*dbg2
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1403 | stefanct | 2011-08-04 19:37:58 +0200 (Thu, 04 Aug 2011) | 4 lines
+
+Rephrase warnings in chipset_enable.c
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1402 | stefanct | 2011-08-01 20:39:28 +0200 (Mon, 01 Aug 2011) | 22 lines
+
+Switch to AAI for some more SST chips
+
+Enable AAI for:
+SST25VF016B
+SST25VF040B{,.REMS}
+SST25VF080B
+
+Chips that support AAI via a different opcode are annotated with a comment:
+SST25VF040.REMS
+SST25LF040A.RES
+
+SST25VF080B
+Tested-by: Joshua Roys <roysjosh@gmail.com>
+Write time (w/erase) went from 46 s to 21 s.
+
+SST25VF016B
+Tested-by: No?\195?\169 Rubinstein <nrubinstein@avencall.com>
+Write time (w/erase) on a dediprog went from 143 mins to 56 mins.
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Rebased and
+Acked-by: No?\195?\169 Rubinstein <nrubinstein@avencall.com>
+------------------------------------------------------------------------
+r1401 | uwe | 2011-07-29 22:13:45 +0200 (Fri, 29 Jul 2011) | 11 lines
+
+Use __func__ instead of __FUNCTION__ as we do elsewhere.
+
+The __func__ variant is standardized in C99 and recommended to be
+used instead of __FUNCTION__ in the gcc info page.
+
+See also r711 where we did the same change.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1400 | uwe | 2011-07-29 14:13:01 +0200 (Fri, 29 Jul 2011) | 9 lines
+
+Make flashrom build on PPC/PowerPC with just "make".
+
+Build-tested in a QEMU ppc (Debian) image, and by Andrew Morgan
+<ziltro@ziltro.com> on real hardware.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Andrew Morgan <ziltro@ziltro.com>
+
+
+------------------------------------------------------------------------
+r1399 | stefanct | 2011-07-29 14:06:04 +0200 (Fri, 29 Jul 2011) | 7 lines
+
+extract spi_prettyprint_status_register_amic_a25_srwd
+
+extract spi_prettyprint_status_register_amic_a25_srwd from
+spi_prettyprint_status_register_amic_a25l* functions
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1398 | uwe | 2011-07-28 21:23:09 +0200 (Thu, 28 Jul 2011) | 6 lines
+
+manpage: Document all ft2232_spi and serprog variants.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1397 | uwe | 2011-07-28 10:13:25 +0200 (Thu, 28 Jul 2011) | 11 lines
+
+Random whitespace and coding-style fixes.
+
+Also, indentation fixes, e.g. due to conversion to msg_*, use ARRAY_SIZE
+where possible, wrap overly long line, etc.
+
+Compile-tested. There should be no functional changes.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1396 | hailfinger | 2011-07-27 09:13:06 +0200 (Wed, 27 Jul 2011) | 7 lines
+
+Rename CHIP_BUSTYPE_FOO to BUS_FOO.
+
+It's shorter to type, and we have less problems with the 80 column limit.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1394 | hailfinger | 2011-07-26 22:43:13 +0200 (Tue, 26 Jul 2011) | 7 lines
+
+Increase flashrom release number to 0.9.4
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1393 | stefanct | 2011-07-26 16:33:46 +0200 (Tue, 26 Jul 2011) | 14 lines
+
+add a bunch of new/tested stuff and various small changes 6
+
+- add J-7BXAN to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007397.html
+
+- fix urls, typos, whitespace etc.
+
+- fix counting of supported chips in the wiki output
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+the last one is
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+everything else is
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1392 | stefanct | 2011-07-26 16:28:35 +0200 (Tue, 26 Jul 2011) | 9 lines
+
+Fix output of erase_and_write_flash and surroundings
+
+see http://www.flashrom.org/pipermail/flashrom/2011-July/007220.html
+for a discussion about the details.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1391 | hailfinger | 2011-07-26 16:18:52 +0200 (Tue, 26 Jul 2011) | 9 lines
+
+Fix Winbond W29EE011, W29EE012, W29C010M, W29C011A probing.
+According to the datasheets probe_w29ee011 is the only valid probe
+function for those chips, but we have reports where those chips
+were only detected with probe_jedec, and thus we assume that our
+datasheets only cover an earlier stepping.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1390 | stefanct | 2011-07-26 02:54:42 +0200 (Tue, 26 Jul 2011) | 18 lines
+
+be more refined regarding DMI chassis types
+
+we had broken laptops in the past that were not detected as such because
+their DMI chassis-type was either undefined/out-of-spec, or set to
+'other' or 'unknown'.
+
+this patch tries to mitigate this problem as follows:
+- if the DMI chassis-type clearly identifies the system as
+  laptop/notebook/mobile platform then nothing changes: the user gets
+  the laptop warning without a hint to the force switch.
+- if the DMI chassis-type is not specific enough, we warn the user
+  similarly, but tell them the switch.
+
+to reduce the number of false positives i have added a few new
+chassis types that we have encountered in the last months to the list.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1389 | hailfinger | 2011-07-26 00:44:09 +0200 (Tue, 26 Jul 2011) | 9 lines
+
+Fix ICH FWH IDSEL setting with the fwh_idsel= internal programmer
+parameter.
+The code took 32 bits of input and wrote them to an 48 bit register,
+duplicating some values.
+Document the fwh_idsel= parameter in the man page.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1388 | hailfinger | 2011-07-26 00:07:05 +0200 (Tue, 26 Jul 2011) | 7 lines
+
+satamv and atahpt require PCI port I/O which isn't currently supported
+on any architecture except x86/x86_64.
+Generate the same compiler error as other programmer drivers.
+
+Signed-off-by: Andrew Morgan <ziltro@ziltro.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1387 | uwe | 2011-07-25 23:12:57 +0200 (Mon, 25 Jul 2011) | 6 lines
+
+Random manpage improvements and updates.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1386 | stefanct | 2011-07-25 22:38:52 +0200 (Mon, 25 Jul 2011) | 47 lines
+
+add a bunch of new/tested stuff and various small changes 5
+
+- mark EN25F80 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007329.html
+- mark W25Q16 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007151.html
+- mark W39V040A as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007161.html
+- mark Pm25LV040 as fully tested
+  reported by TL1 on IRC
+- mark W49F002U/N as fully tested
+  http://paste.flashrom.org/view.php?id=733g
+- mark W39V080FA as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007225.html
+
+- add ASUS P4S533-X to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007200.html
+- add ASUS M4A785TD-V EVO to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007329.html
+- add GA-945PL-S3P (rev. 6.6) to the list of supported boards
+  reported by TL1 on IRC
+- add MS-7142 (K8MM-V) to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007161.html
+- add MS-7369 (K9N Neo V2) to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007181.html
+- add X7DBT-INF to the list of supported boards
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007225.html
+
+- mark SiS 645DX chipset enable as OK
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007200.html
+- mark SiS 651 chipset enable as OK
+  http://paste.flashrom.org/view.php?id=733
+
+- move intel_ich_gpio34_raise to the correct line(s)
+- change the output of unlock_w39_fwh_block from 0x%x to 0x%08x
+- fix output for untested chipset enables (missing space)
+- reorder the board enable in print.c entry for GA-8SIMLH added in r1385.
+- minor other fixes
+
+- fix output for multiple found flash chips by adding quotes and commas
+- similarly fix output of "Found/Assuming" chips
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+the last two points are
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+everything else is
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1385 | mkarcher | 2011-07-25 19:25:24 +0200 (Mon, 25 Jul 2011) | 14 lines
+
+Add support for the GIGABYTE GA-8SIMLH board.
+
+The usage of the GPIO output register as bitmap can be confirmed from the
+vendor board enable code, so the comment has been deleted. It really is
+(1<<gpionumber).
+
+flashrom -V: http://paste.flashrom.org/view.php?id=728
+lspci: http://paste.flashrom.org/view.php?id=729
+superiotool: http://paste.flashrom.org/view.php?id=730
+
+test report: http://paste.flashrom.org/view.php?id=733
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1384 | stefanct | 2011-07-25 00:21:57 +0200 (Mon, 25 Jul 2011) | 13 lines
+
+add support for EN25Q(H) series SPI flash chips
+
+- EN25Q40
+- EN25Q80
+- EN25Q16 (half-evil twin of already supported EN25D16, hence merged)
+- EN25Q32(A/B)
+- EN25Q64
+- EN25Q128
+
+- EN25QH16
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1383 | hailfinger | 2011-07-24 20:41:13 +0200 (Sun, 24 Jul 2011) | 9 lines
+
+Man page fixes:
+- Finish dummy programmer description
+- Add satamv programmer
+- Merge it87spi programmer into internal section
+- Cosmetics
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1382 | stefanct | 2011-07-24 18:30:31 +0200 (Sun, 24 Jul 2011) | 11 lines
+
+mark some ck804 boards as not working
+
+P5N-E SLI, EP-8NPA7I and EP-9NPA7I all need at least this patch:
+http://patchwork.coreboot.org/patch/2125/
+the P5N-E also needs a board enable:
+http://patchwork.coreboot.org/patch/3298/
+
+mark the boards as not working until those are merged.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1381 | stefanct | 2011-07-24 17:34:56 +0200 (Sun, 24 Jul 2011) | 10 lines
+
+ichspi.c: do not print PBR[3] for ICH7 because it does not exist
+
+intel document 307013 (ICH7 datasheet) section 21.1.9 does only
+define PBR[0] (at SPIBAR + 60h) to PBR[2] (SPIBAR + 68h). SPIBAR + 6Ch
+and following are not defined, but we were printing them as PBR[3]
+anyway. i could not find any references to PBR[3] in documentation of
+other related chips (NM10, atom e6xx) either, hence kill it.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1380 | hailfinger | 2011-07-21 23:21:04 +0200 (Thu, 21 Jul 2011) | 9 lines
+
+Fix out-of-bounds access if all erase functions fail.
+Fix detection of unchanged chip contents on erase failure.
+Return error if no usable erase functions exist.
+
+Thanks to Stefan Tauner for spotting the last problem.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1379 | stefanct | 2011-07-21 21:59:34 +0200 (Thu, 21 Jul 2011) | 22 lines
+
+chipset_enable.c: add a message for untested chipset enables
+
+old output:
+Calibrating delay loop... OK.
+Found chipset "Intel QS57", enabling flash write... OK.
+This chipset supports the following protocols: FWH, SPI.
+
+new non-verbose output for tested chipsets:
+Calibrating delay loop... OK.
+Found chipset "Intel QS57". Enabling flash write... OK.
+This chipset supports the following protocols: FWH, SPI.
+
+new non-verbose output for untested chipsets:
+Found chipset "Intel QS57".
+This chipset is marked as untested. If you are using an up-to-date version
+of flashrom please email a report to flashrom@flashrom.org including a
+verbose (-V) log. Thank you!
+Enabling flash write... OK.
+This chipset supports the following protocols: FWH, SPI.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1378 | stefanct | 2011-07-21 21:52:00 +0200 (Thu, 21 Jul 2011) | 5 lines
+
+flashrom.8: explain read accesses as part of the write operation
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Paul Menzel <paulepanter@users.sourceforge.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1377 | uwe | 2011-07-21 11:18:18 +0200 (Thu, 21 Jul 2011) | 15 lines
+
+ft2232_spi: Improve error handling, remove exit() calls.
+
+In order to make the ft2232_spi code more usable in libflashrom (e.g. from
+frontends/GUIs) there must not be any exit() calls in the code, as that
+would also terminate the frontend. Thus, replace all exit() calls with
+proper error handling code by returning a _unique_ negative error number,
+so that the frontend (and/or user/developer) can also know a bit more
+exactly _which_ error occured, not only _that_ an error occured.
+
+Also, call ftdi_usb_close() before returning due to errors.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Tadas Slotkus <devtadas@gmail.com>
+
+
+------------------------------------------------------------------------
+r1376 | stefanct | 2011-07-20 18:34:18 +0200 (Wed, 20 Jul 2011) | 8 lines
+
+fix the ASUS A8N-VM CSM board enable
+
+based on joshua's work, see:
+http://www.flashrom.org/pipermail/flashrom/2011-June/007015.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Joshua Roys <roysjosh@gmail.com>
+Tested-by: Bernie Innocenti <bernie@fsf.org>
+------------------------------------------------------------------------
+r1375 | stefanct | 2011-07-19 10:50:18 +0200 (Tue, 19 Jul 2011) | 7 lines
+
+annotate additional flashchips with voltage ranges
+
+also fix a few others and remove the one for Intel 28F002BC/BL/BV/BX-T because we need
+to investigate it further.
+
+Signed-off-by: Steven Zakulec <spzakulec@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1374 | stefanct | 2011-07-19 09:58:06 +0200 (Tue, 19 Jul 2011) | 8 lines
+
+fix a bug breaking layout file handling in r1373
+
+Florian Zumbiehl discovered that we have broken the -i switch in the
+last commit resulting in self-contradictory output:
+http://paste.flashrom.org/view.php?id=707
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1373 | hailfinger | 2011-07-16 01:47:45 +0200 (Sat, 16 Jul 2011) | 11 lines
+
+Fix and clean up cli_classic.c
+
+Don't ignore -i if it is specified before -l
+Check if image mentioned by -i is present in layout file
+Consolidate duplicated programmer_shutdown calls
+Kill outdated comments
+Finish parameter checking before -L/-z is executed
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1372 | stefanct | 2011-07-13 22:48:54 +0200 (Wed, 13 Jul 2011) | 6 lines
+
+enable writing on mcp6x_7x
+
+this was deliberately disabled until now, but seems to work well enough.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1371 | uwe | 2011-07-13 13:22:03 +0200 (Wed, 13 Jul 2011) | 11 lines
+
+Change "class" parameter name to "devclass" to avoid C++ issues.
+
+In C++ "class" is a reserved keyword, and as we'll want to use libflashrom
+from C++ code at some point, let's make sure it doesn't cause issues.
+Other places in the code already used "devclass" anyway, so it also increases
+consistency and readability a bit.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1370 | stefanct | 2011-07-13 00:35:21 +0200 (Wed, 13 Jul 2011) | 9 lines
+
+fix unchecked malloc calls and casts of malloc return values
+
+in the long term the exit calls should be replaced by returns.
+until then this is the correct way to handle failures.
+
+the casts are not needed (in C) and we don't cast malloc return values anywhere else.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1369 | stefanct | 2011-07-13 00:01:44 +0200 (Wed, 13 Jul 2011) | 6 lines
+
+update motherboard URLs in print.c
+
+Signed-off-by: Benjamin Bellec <b.bellec@gmail.com>
+with small changes:
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1368 | stefanct | 2011-07-09 21:46:53 +0200 (Sat, 09 Jul 2011) | 10 lines
+
+add untested board enable for ASUS M6Ne
+
+http://patchwork.coreboot.org/patch/2893/
+lspci: http://paste.flashrom.org/view.php?id=494
+
+only writing a backup file was tested, so mark it as untested.
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1367 | stefanct | 2011-07-07 21:56:58 +0200 (Thu, 07 Jul 2011) | 57 lines
+
+add a bunch of new/tested stuff and various small changes 4
+
+- add Asus E35M1-I DELUXE to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006918.html
+- add Asus M3A to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007085.html
+- add Freetech P6F91i to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006800.html
+- add GA-M720-US3 to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007096.html
+- add GA-MA770-UD3 (rev. 2.1) to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006879.html
+- add GA-965GM-S2 to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006746.html
+- add HP xw4400 (0A68h) to boards_known
+  http://paste.flashrom.org/view.php?id=686
+- add MSI MS-6566 (845 Ultra-C) to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006908.html
+- add MSI MS-7698 (E350IA-E45) to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-June/007003.html
+- add PCCHIPS M863G (V5.1A) to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007084.html
+
+- modify the X8SIE entry in boards_known with the information from "fuzzy"
+  http://paste.flashrom.org/view.php?id=669
+
+- mark W29C020(C)/W29C022 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006800.html
+- mark W49V002A as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007084.html
+- mark M25P128 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006843.html
+- mark SST39SF010A as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-July/007115.html
+
+- correct entries for GA-K8NS Pro-939 (was ultra before. thanks uwe!)
+- another tiny fix for "a small fix"/r1321
+  Without this you will get broken bus names "Unknow" and "Non-SP".
+  Note to self: don't self-ack even fairly trivial patches.
+- fix spew output of spi_rems in spi25.c
+- add URL to ASUS M3A76-CM
+- rename all Winbond W25x chips to W25X
+- fixes some common misspellings/typos in comments:
+  lenght->length              2
+  ocassional->occasional      1
+  unsucessfull->unsuccessful  1
+  upto->up to                 5
+
+the patch for M25P128 is
+Signed-off-by: Cristian M?\196?\131gheru?\200?\153an-Stanciu <cristi.magherusan@gmail.com>
+
+the typos are
+Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
+
+everything else is
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1366 | hailfinger | 2011-07-07 08:59:18 +0200 (Thu, 07 Jul 2011) | 7 lines
+
+Autodetect target processor architecture.
+Enable architecture dependent compilation of individual sub-drivers for
+the internal programmer.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1365 | stefanct | 2011-07-07 06:10:57 +0200 (Thu, 07 Jul 2011) | 7 lines
+
+ichspi.c: print FADDR in ich_init_spi
+
+We print the address registers for ICH7 and VIA at init.
+We should do so for ICH9 too.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: David Hendricks <dhendrix@google.com>
+------------------------------------------------------------------------
+r1364 | stefanct | 2011-07-04 09:27:17 +0200 (Mon, 04 Jul 2011) | 4 lines
+
+Kill unused "log" argument of count_usable_erasers().
+
+Signed-off-by: Sylvain "ythier" Hitier <sylvain.hitier@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1363 | uwe | 2011-07-03 21:44:12 +0200 (Sun, 03 Jul 2011) | 25 lines
+
+Fix and improve Windows/MinGW/MSYS build.
+
+ - Makefile: Use $(OS_ARCH) to add some MinGW-specific workarounds and
+   settings, so that a simple "make" is sufficient on MinGW (instead of
+   manual Makefile hacking).
+
+ - Explicitly set CC=gcc in the Makefile, otherwise you get an error like
+   "cc: command not found" on MinGW.
+
+ - MinGW doesn't have ffs(), use gcc's __builtin_ffs() instead.
+
+ - Add /usr/local/include and /usr/local/lib to CPPFLAGS/LDFLAGS, that's
+   where libusb-win32 and libftdi stuff is usually placed on MinGW/MSYS.
+
+ - Disable serprog (no sockets) and all PCI-based programmers (no libpci)
+   for now. That leaves dummy, ft2232_spi, and buspirate_spi enabled on
+   MinGW per default.
+
+ - serial.c: Use correct type for 'tmp', both on Windows/MinGW (DWORD)
+   and POSIX (ssize_t).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1362 | stefanct | 2011-07-01 02:39:23 +0200 (Fri, 01 Jul 2011) | 4 lines
+
+ichspi.c: preserve reserved bits in address registers
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1361 | stefanct | 2011-07-01 02:39:16 +0200 (Fri, 01 Jul 2011) | 4 lines
+
+ichspi.c: add FPB (Flash Partition Boundary) macros and init printing
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1360 | stefanct | 2011-07-01 02:39:09 +0200 (Fri, 01 Jul 2011) | 6 lines
+
+ichspi.c: simplify ich_set_bbar
+
+Less code, documenting better what the differences are (i.e. offset of BBAR only).
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1359 | stefanct | 2011-07-01 02:39:01 +0200 (Fri, 01 Jul 2011) | 8 lines
+
+ichspi.c: make REGWRITE* macros safer
+
+'+' does have a quite high precedence so "calling" those macros with a
+term including weaker operators in the off parameter may have unexpected
+consequences.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1358 | stefanct | 2011-07-01 02:19:12 +0200 (Fri, 01 Jul 2011) | 8 lines
+
+add count_usable_erasers which returns the number of well-defined erasers for a chip
+
+It solves one FIXME and consequentially allows to remove a later check
+right now, and is used in the upcoming SFDP patch.
+Adds a forward declaration of check_block_eraser.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1357 | stefanct | 2011-06-26 22:45:35 +0200 (Sun, 26 Jun 2011) | 4 lines
+
+fix memleaks due to incorrect usage of flashbuses_to_text
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1356 | stefanct | 2011-06-26 20:28:58 +0200 (Sun, 26 Jun 2011) | 11 lines
+
+make Makefile's test programs safe(r)
+
+we don't use -W or similarly strict compiler checks (yet), but
+enabling its use is a good thing. if you add -W to the cflags
+without this patch, detection of the compiler will fail with gcc 4.4
+for example, because compiling of the test program will fail due to
+a warning of unused arguments and -Werror. similarly the other
+checks involving compiling test programs would fail.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1355 | stefanct | 2011-06-26 19:47:40 +0200 (Sun, 26 Jun 2011) | 4 lines
+
+add a success indicator to the "Reading old flash chip contents..." message
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1354 | stefanct | 2011-06-26 19:38:17 +0200 (Sun, 26 Jun 2011) | 4 lines
+
+constify (a few) parameters in flashrom.c where possible
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1353 | hailfinger | 2011-06-26 19:04:16 +0200 (Sun, 26 Jun 2011) | 9 lines
+
+Erase functions are no longer called from chip drivers and thus their
+internal erase verification can be moved to generic code.
+This also makes it easier to skip the verify step if desired and to
+differentiate between failed command submission and failed erase
+verification.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1352 | hailfinger | 2011-06-26 13:50:10 +0200 (Sun, 26 Jun 2011) | 12 lines
+
+Replace sizeof("string")-1 with strlen("string")
+
+We want to avoid calls to strlen at runtime if the string is already
+known at compile time.
+Turns out that gcc and clang will recognize constant strings and compute
+the strlen result already at compile time, so trickery with sizeof only
+reduces readability but does not improve the code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1351 | stefanct | 2011-06-25 19:36:25 +0200 (Sat, 25 Jun 2011) | 4 lines
+
+print.c: change all occurrences of printf to msg_ginfo
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1350 | stefanct | 2011-06-25 19:04:26 +0200 (Sat, 25 Jun 2011) | 7 lines
+
+fix probe_flash to report new values set by probing functions
+
+This is needed if the probing function changes its fill_flash parameter
+like in the pattern used to support Intel Hardware Sequencing and SFDP.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1349 | uwe | 2011-06-19 19:27:57 +0200 (Sun, 19 Jun 2011) | 11 lines
+
+Currently messages like "Writing flash chip..." that don't end with a
+newline are buffered until the operation is complete, unless the
+particular write function generates status output in the meantime.
+
+Flushing stdout after each message ensures that the message appears
+immediately.
+
+Signed-off-by: Ed Swierk <eswierk@aristanetworks.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1348 | uwe | 2011-06-19 19:23:55 +0200 (Sun, 19 Jun 2011) | 6 lines
+
+flashchips.c: Fix typo: s/don't/doesn't/.
+
+Signed-off-by: Paul Menzel <paulepanter@users.sourceforge.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1347 | uwe | 2011-06-19 19:09:49 +0200 (Sun, 19 Jun 2011) | 6 lines
+
+Look at the return value of wait_82802ab().
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1346 | uwe | 2011-06-19 18:52:48 +0200 (Sun, 19 Jun 2011) | 8 lines
+
+Add ASRock K7S41GX board-enable.
+
+Tested reading, writing and verification, all worked fine.
+
+Signed-off-by: Pawel Rozanski <rozie@poczta.onet.pl>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1345 | uwe | 2011-06-19 00:56:14 +0200 (Sun, 19 Jun 2011) | 43 lines
+
+Various board status updates.
+
+Mark the following boards as OK:
+
+ - ASUS P7H57D-V EVO (reported by Andrew Wierzan <andrew@emerginguk.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-October/005042.html
+
+ - Tyan S2723 (Tiger i7501) (reported by Uwe Hermann <uwe@hermann-uwe.de>)
+   http://www.flashrom.org/pipermail/flashrom/2010-October/005156.html
+
+ - ASUS P5VD1-X (reported by Olle Gross <gusgross@student.gu.se>)
+   http://www.flashrom.org/pipermail/flashrom/2010-October/005205.html
+
+ - Lanner EM-8510C (reported by Christian Motz <christian.motz@funkwerk-ec.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-October/005240.html
+
+ - ASUS A8N-VM (reported by Dave B <flashrom@d10.karoo.co.uk>)
+   http://www.flashrom.org/pipermail/flashrom/2010-October/005247.html
+
+ - GIGABYTE GA-6VXE7+ (reported by Justin Doiel <justin.doiel@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-October/005251.html
+
+ - Supermicro X7SPA-HF (reported by Jochen Schulz <ml@well-adjusted.de>)
+   http://www.flashrom.org/pipermail/flashrom/2010-November/005346.html
+
+ - ASUS M4A78-EM (reported by Jani Uusitalo <jani@mummila.net>)
+   http://www.flashrom.org/pipermail/flashrom/2010-December/005587.html
+
+ - ASUS P5N32-E SLI (reported by Paul Brookman <paul_brookman@sky.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-December/005559.html
+
+Mark the following chips as OK:
+
+ - SST SST39SF020A (reported by Andrew Morgan <ziltro@ziltro.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-October/005107.html
+
+ - ST M25P80 (reported by Harald Gutmann <harald.gutmann@gmx.net>)
+   http://www.flashrom.org/pipermail/flashrom/2010-November/005334.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1344 | stefanct | 2011-06-18 20:45:56 +0200 (Sat, 18 Jun 2011) | 7 lines
+
+add intel 6 series pci ids to chipset_enables
+
+as defined by Intel 6 Series Chipset and Intel C200 Series Chipset Specification Update;
+document number 324646-006, May 2011.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1343 | stefanct | 2011-06-18 20:45:50 +0200 (Sat, 18 Jun 2011) | 5 lines
+
+fix and add a few chipset_enables entries
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1342 | stefanct | 2011-06-18 20:45:41 +0200 (Sat, 18 Jun 2011) | 5 lines
+
+resort chipset_enables array by pci ids
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1341 | hailfinger | 2011-06-18 00:38:53 +0200 (Sat, 18 Jun 2011) | 6 lines
+
+Do not display skipped probe messsages in verbose mode.
+They are still visible in spew mode (-VV).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1340 | uwe | 2011-06-17 23:25:48 +0200 (Fri, 17 Jun 2011) | 14 lines
+
+Update the flashrom udev rules file with new programmers.
+
+Add the following missing USB devices:
+
+ - FIC OpenMoko Neo1973 Debug board (V2+)
+ - Olimex ARM-USB-OCD
+ - Olimex ARM-USB-OCD-H
+ - Olimex ARM-USB-TINY
+ - Olimex ARM-USB-TINY-H
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+
+------------------------------------------------------------------------
+r1339 | stefanct | 2011-06-16 01:44:52 +0200 (Thu, 16 Jun 2011) | 12 lines
+
+Update the flashrom manpage
+
+ - Add missing entries for nicintel and satamv.
+ - Add various programmers to those that support the 'pci=' option.
+ - Small cosmetic, whitespace, grammar or consistency fixes.
+ - Update the date of last change of the manpage.
+ - Add Stefan Tauner to the list of authors.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Signed-off-by: Andrew Morgan <ziltro@ziltro.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1338 | dhendrix | 2011-06-14 03:35:36 +0200 (Tue, 14 Jun 2011) | 26 lines
+
+Use shutdown callback mechanism to shutdown programmers
+
+This patch attempts to resolve some programmer shutdown ordering issues
+by having the programmer init functions register shutdown callbacks explicitly
+wherever it makes most sense. Before, assumptions were made that could lead to
+the internal programmer's state changing before the external programmer could be
+shut down properly. Now, each programmer cleans up after itself and (hopefully)
+performs each operation in the correct order.
+
+As a side-effect, this patch gives us a better usage model for reverse
+operations such as rpci_* and rmmio_*. In the long-run, this should make
+reversing the initialization process easier to understand, less tedious, and
+less error-prone.
+
+In short, this patch does the following:
+- Registers a shutdown callback during initialization for each programmer.
+- Kills the .shutdown function pointer from programmer_entry struct. Also,
+  make most shutdown functions static.
+- Adds a few minor clean-ups and corrections (e.g. missing physunmap() calls).
+
+TODO: Remove forward declaration of serprog_shutdown() (added to simplify diff)
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1337 | stefanct | 2011-06-13 18:59:01 +0200 (Mon, 13 Jun 2011) | 9 lines
+
+add board enable for GA-8IP775
+
+- logs before: http://paste.flashrom.org/view.php?id=565
+- success: http://www.flashrom.org/pipermail/flashrom/2011-June/006747.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1336 | stefanct | 2011-06-13 18:58:54 +0200 (Mon, 13 Jun 2011) | 10 lines
+
+add (untested) board enable for GA-K8NS Pro-939
+
+flashrom -V (before patch): http://paste.flashrom.org/view.php?id=531
+lspci (short): http://paste.flashrom.org/view.php?id=532
+lspci (verbose): http://paste.flashrom.org/view.php?id=533
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1335 | stefanct | 2011-06-12 21:47:55 +0200 (Sun, 12 Jun 2011) | 24 lines
+
+add a bunch of new/tested motherboards, board/chipset enables and flash chips etc 3
+
+- mark AT25DF321 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/attachments/20110527/01f1868b/attachment-0001.log
+- mark 82802AB as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-April/006145.html
+- mark Pm49FL002 as fully tested
+  http://pastebin.com/pb5NTCmW
+
+- add Supermicro X8DT3 to boards_known
+  http://www.flashrom.org/pipermail/flashrom/attachments/20110527/01f1868b/attachment-0001.log
+- add Supermicro X5DP8-G2 to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-April/006145.html
+
+- add Supermicro X8SIE as NOT WORKING to boards_known
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006554.html
+- add a DMI search pattern for the ASUS A8N-SLI Deluxe board enable to mitigate misdetections
+  http://www.flashrom.org/pipermail/flashrom/2010-August/004379.html
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006570.html
+
+also, fix some random white space errors and comments/strings
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1334 | stefanct | 2011-06-12 10:14:10 +0200 (Sun, 12 Jun 2011) | 8 lines
+
+ichspi.c: add missing ICH9 register macros and eliminate magic numbers
+
+ - add macros for FRAP, FREG0, PR0-PR4 and BBAR
+ - eliminate magic numbers representing those registers and some other bits too
+ - remove printing out the contents of FDOC because it is useless
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1333 | stefanct | 2011-06-11 21:44:31 +0200 (Sat, 11 Jun 2011) | 7 lines
+
+use the max_data_read field of the new spi_programmer struct to simplify run_opcode
+
+also, explain the transformation of the read/write array/count in
+ich_spi_send_command better.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1332 | stefanct | 2011-06-11 20:16:50 +0200 (Sat, 11 Jun 2011) | 4 lines
+
+enable_flash_ich: warn if SMM BIOS Write Protection is detected in BIOS_CNTL
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1331 | stefanct | 2011-06-11 14:21:37 +0200 (Sat, 11 Jun 2011) | 7 lines
+
+add support for Olimex programmers to ft2232_spi
+
+- add support for Olimex' ARM-USB-TINY, ARM-USB-TINY-H, ARM-USB-OCD AND ARM-USB-OCD-H and adjust man page
+- minor string change ("First International Computer, Inc." -> "FIC")
+
+Signed-off-by: Pete Batard <pbatard@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1330 | stefanct | 2011-06-11 11:53:22 +0200 (Sat, 11 Jun 2011) | 4 lines
+
+ichspi.c: add macros and pretty printing for HSFS and HSFC
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1329 | stefanct | 2011-06-11 11:53:16 +0200 (Sat, 11 Jun 2011) | 4 lines
+
+ichspi.c: add pretty printing for SSFS+SSFC and the OPCODE struct
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1328 | stefanct | 2011-06-11 11:53:09 +0200 (Sat, 11 Jun 2011) | 12 lines
+
+ichspi.c: improve macros for SSFS and SSFC bits
+
+ - introduce offset macros and use them to (re)define the existing mask macros
+ - fix masks of SSFC_COP, SSFC_DBC, SSFC_SCF (were single-bit masks erroneously)
+ - add comments
+ - rename SSFS_CDS to SSFS_FDONE (abbr. used in datasheet; not in SSFS but HSFS)
+ - use those for refactoring and magic number elemination.
+
+ following patch uses them for pretty printing.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1327 | hailfinger | 2011-06-09 22:59:30 +0200 (Thu, 09 Jun 2011) | 8 lines
+
+Add board enable for MSI MS-6788-040 (848P Neo-V).
+
+Based on reverse engineering by Michael Karcher.
+Signed-off-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Tested-by: Melroy van den Berg
+http://www.flashrom.org/pipermail/flashrom/2010-December/005642.html
+
+------------------------------------------------------------------------
+r1326 | hailfinger | 2011-06-09 22:06:34 +0200 (Thu, 09 Jun 2011) | 10 lines
+
+Fix compilation for CONFIG_INTERNAL=no
+
+CONFIG_INTERNAL implies Super I/O support and NEED_PCI.
+NEED_PCI is only used to guard PCI stuff which may be needed for
+external PCI-based programmers. That way, using #if NEED_PCI can be
+avoided inside #if CONFIG_INTERNAL.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1325 | uwe | 2011-06-06 19:50:20 +0200 (Mon, 06 Jun 2011) | 13 lines
+
+Mark the MSI MS-7529 (G31TM-P21) as supported.
+
+Original report:
+http://www.flashrom.org/pipermail/flashrom/2011-May/006594.html
+
+Manufacturer's page:
+http://msi.com/product/mb/G31TM-P21.html
+
+Tested-by: Peter Lemenkov <lemenkov@gmail.com>
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1324 | stefanct | 2011-06-04 15:13:34 +0200 (Sat, 04 Jun 2011) | 21 lines
+
+add a bunch of new/tested motherboards, board/chipset enables and flash chips 2
+
+- mark chipset enable for QS57 as OK
+  (my thinkpad)
+
+- mark MSI G31M3-L(S) V2 (MS-7529) as OK
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006634.html
+
+- mark AT49BV512 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006609.html
+- mark MX25L4005 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006634.html
+- mark SST49LF020 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006570.html
+- mark SST25VF064C as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006586.html
+- mark W25x16 as fully tested
+  http://www.flashrom.org/pipermail/flashrom/2011-June/006605.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1323 | stefanct | 2011-06-03 09:26:31 +0200 (Fri, 03 Jun 2011) | 5 lines
+
+Add voltage ranges to the flashchips
+
+Signed-off-by: Steven Zakulec <spzakulec@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Peter Stuge <peter@stuge.se>
+------------------------------------------------------------------------
+r1322 | stefanct | 2011-05-29 00:59:05 +0200 (Sun, 29 May 2011) | 10 lines
+
+tiny fix for a small fix
+
+there was one line break added too much in the previous commit, sorry.
+the probing functions need to output at least one '\n' for satisfactory output.
+that means even in error cases they have to do that.
+OTOH they should not output a sequence of "\n\n" because
+it would distort the verbose probing output with empty lines.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1321 | stefanct | 2011-05-28 04:37:14 +0200 (Sat, 28 May 2011) | 8 lines
+
+small fixes
+
+- missing spaces in code and output
+- improved documentation/naming/output
+- missing line breaks in spi probing functions
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1320 | stefanct | 2011-05-26 16:28:51 +0200 (Thu, 26 May 2011) | 35 lines
+
+add a bunch of new/tested motherboards, board enables and flash chips
+
+tested motherboards:
+- MSI MS-7599 (870-C45)
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006420.html
+- Gigabyte GA-P55A-UD4 (rev 1.0)
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006415.html
+- Supermicro X8DTU-F
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006329.html
+- Supermicro X8STi
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006436.html
+
+tested board enable:
+- abit NF-M2 nView
+  success report (without a log though): http://www.flashrom.org/pipermail/flashrom/2011-April/006167.html
+
+tested flash chips:
+- ST M50FW080 (+EW)
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006409.html
+- ST M25P32 (+EW)
+  http://www.flashrom.org/pipermail/flashrom/2011-May/006398.html
+- Winbond W25x64 (+P)
+  http://www.flashrom.org/pipermail/flashrom/2011-March/006012.html
+- Winbond W39V040FA (+W)
+  http://www.flashrom.org/pipermail/flashrom/2010-December/005642.html
+
+new flash chip
+- Winbond W25Q128
+  http://www.flashrom.org/pipermail/flashrom/2011-April/006309.html
+
+W25Q128 is:
+Signed-off-by: Antony Rheneus <rheneus.paul@gmail.com>
+everything else is:
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1319 | stefanct | 2011-05-26 15:30:51 +0200 (Thu, 26 May 2011) | 4 lines
+
+ichspi: fix detection of unused regions
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1318 | stefanct | 2011-05-26 03:35:19 +0200 (Thu, 26 May 2011) | 8 lines
+
+eliminate magic numbers indicating maximum column sizes in print_supported_chipsets and print_supported_boards_helper
+
+without this the magic numbers need to be kept in sync with the maximum length of the
+strings printed in the corresponding column. if not, an overflow and a nasty ' '-storm occur
+on executing flashrom -L.
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1317 | stefanct | 2011-05-19 04:58:17 +0200 (Thu, 19 May 2011) | 12 lines
+
+whitespace, documentation and other small stuff
+
+this patch combines three previously posted patches in a revised form.
+one is even stolen from Stefan Reinauer (remove umlauts from man page).
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Signed-off-by: Stefan Reinauer <reinauer@google.com>
+
+some parts are
+Acked-by: Carl-Daniel Hailfinger<c-d.hailfinger.devel.2006@gmx.net>
+the rest is
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1316 | hailfinger | 2011-05-19 02:06:06 +0200 (Thu, 19 May 2011) | 24 lines
+
+Add lock printing for AMIC A25L05PT, A25L05PU, A25L10PT, A25L10PU,
+A25L20PT, A25L20PU, A25L40PT, A25L40PU, A25L80P, A25L16PT, A25L16PU,
+A25L512, A25L010, A25L020, A25L040, A25L080, A25L016, A25L032, A25LQ032
+to a25.c.
+
+Add lock printing for Atmel AT26DF081A, AT26DF161, AT26DF161A, AT26DF321.
+
+Move Atmel AT25*/AT26* lock related functions originally added in r1115
+from spi25.c to at25.c.
+
+For SPI chips the lock printing was handled by one common function, but
+sharing a common function which only is a big switch() statement doesn't
+make sense, especially if we can define lock printing functions per flash
+chip anyway.
+
+The printlock function pointer in struct flashchip is used to print status
+register and locking information, and serves as replacement for implicit
+status register and lock printing during probe.
+That code will later be changed to store locking info in a machine-
+accessible data structure so flashrom can handle locked regions correctly.
+
+Signed-off-by: Carl-Daniel Hailfinger<c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+
+------------------------------------------------------------------------
+r1315 | stefanct | 2011-05-18 13:28:47 +0200 (Wed, 18 May 2011) | 6 lines
+
+mark SST25VF080B tested for writing (again)
+
+Success report: http://www.flashrom.org/pipermail/flashrom/2011-May/006473.html
+
+Signed-off-by: John Schmerge <jschmerge@gmail.com>
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1314 | stefanct | 2011-05-18 03:32:25 +0200 (Wed, 18 May 2011) | 4 lines
+
+mark Supermicro X8DTH-6F as supported.
+
+Signed-off-by: Shailendra Sodhi <shailendra.sodhi@endace.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1313 | stefanct | 2011-05-18 03:32:16 +0200 (Wed, 18 May 2011) | 7 lines
+
+add board enable for AOpen i975Xa-YDG
+
+Success report:
+http://www.flashrom.org/pipermail/flashrom/2010-October/005046.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Idwer Vollering<vidwer@gmail.com>
+------------------------------------------------------------------------
+r1312 | stefanct | 2011-05-18 03:32:09 +0200 (Wed, 18 May 2011) | 6 lines
+
+mark EVGA 270-WS-W555-A2 (Classified SR-2) as supported.
+
+success report: http://flashrom.org/pipermail/flashrom/2011-April/006179.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1311 | stefanct | 2011-05-18 03:32:00 +0200 (Wed, 18 May 2011) | 6 lines
+
+mark SST25VF032B as write tested
+
+success report: http://flashrom.org/pipermail/flashrom/2011-April/006179.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1310 | stefanct | 2011-05-18 03:31:53 +0200 (Wed, 18 May 2011) | 4 lines
+
+explain better what checks are disabled in case we detect a legacy BIOS
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Peter Stuge <peter@stuge.se>
+------------------------------------------------------------------------
+r1309 | stefanct | 2011-05-18 03:31:46 +0200 (Wed, 18 May 2011) | 7 lines
+
+Mark Macronix MX29F001T as fully tested
+
+Success report with MX29F001TPC-12 at:
+http://flashrom.org/pipermail/flashrom/2011-April/006132.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+------------------------------------------------------------------------
+r1308 | stefanct | 2011-05-18 03:31:39 +0200 (Wed, 18 May 2011) | 6 lines
+
+add Gigabyte GA-MA790XT-UD4P to the mainboard support list
+
+http://www.flashrom.org/pipermail/flashrom/2011-April/006099.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1307 | stefanct | 2011-05-18 03:31:33 +0200 (Wed, 18 May 2011) | 4 lines
+
+add MS-7640 (890FXA-GD70) to the boards_known struct in print.c
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1306 | stefanct | 2011-05-18 03:31:24 +0200 (Wed, 18 May 2011) | 4 lines
+
+add support for 8086:1076 (82541GI) to nicintel_spi.c
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1305 | stefanct | 2011-05-18 03:31:17 +0200 (Wed, 18 May 2011) | 4 lines
+
+add status of Thinkpad T410s and DG45ID to the wiki table
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1304 | stefanct | 2011-05-18 03:31:10 +0200 (Wed, 18 May 2011) | 4 lines
+
+Mark MX25L4005 tested for erase
+
+Signed-off-by: Ra?\195?\186l Soriano <GatoLoko@gmail.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1303 | stefanct | 2011-05-18 03:31:03 +0200 (Wed, 18 May 2011) | 4 lines
+
+Mark w25q80, w25q32, and w25q64 chips tested for write and erase
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+------------------------------------------------------------------------
+r1302 | stefanct | 2011-05-18 03:30:56 +0200 (Wed, 18 May 2011) | 4 lines
+
+Remove filename parameter from chip_safety_check()
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+------------------------------------------------------------------------
+r1301 | stefanct | 2011-05-18 01:30:13 +0200 (Wed, 18 May 2011) | 4 lines
+
+fix typo "not not" in board_enable.c
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r1300 | stefanct | 2011-05-17 15:31:55 +0200 (Tue, 17 May 2011) | 4 lines
+
+add board enable for Asus A8AE-LE (HP OEM)
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1299 | mkarcher | 2011-05-11 19:07:07 +0200 (Wed, 11 May 2011) | 15 lines
+
+kill central list of SPI programmers
+
+Remove the array spi_programmer, replace it by dynamic registration
+instead. Also initially start with no busses supported, and switch to
+the default non-SPI only for the internal programmer.
+
+Also this patch changes the initialization for the buses_supported variable
+from "everything-except-SPI" to "nothing". All programmers have to set the
+bus type on their own, and this enables register_spi_programmer to just add
+the SPI both for on-board SPI interfaces (where the internal programmer
+already detected the other bus types), as well as for external programmers
+(where we have the default "none").
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1298 | mkarcher | 2011-05-11 19:07:02 +0200 (Wed, 11 May 2011) | 4 lines
+
+Factor out SPI write/read chunking wrappers.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1297 | hailfinger | 2011-05-08 02:24:18 +0200 (Sun, 08 May 2011) | 7 lines
+
+Intel NIC with parallel flash support.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Anton Kochkov <anton.kochkov@gmail.com>
+Acked-by: Anton Kochkov <anton.kochkov@gmail.com>
+Tested-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+
+------------------------------------------------------------------------
+r1296 | hailfinger | 2011-05-07 21:19:36 +0200 (Sat, 07 May 2011) | 8 lines
+
+Fix multiple detection of the same chip.
+
+r1293 introduced a bug which caused probing to loop at the first found
+chip.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1295 | mkarcher | 2011-05-05 19:52:07 +0200 (Thu, 05 May 2011) | 4 lines
+
+Add support for the Via VX855 chipset
+
+Signed-off-by: John Schmerge <jbschmerge@gmail.com> for Devon IT
+Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+------------------------------------------------------------------------
+r1294 | hailfinger | 2011-05-05 09:12:40 +0200 (Thu, 05 May 2011) | 22 lines
+
+Revamp board-specific quirk handling, allow for laptop support
+
+Handle board-specific quirks in three phases:
+1. Before Super I/O probing (e.g. blacklisting of some Super I/O probes,
+or unhiding the Super I/O)
+2. Before the laptop enforcement decision (e.g. whitelisting a laptop
+for flashing)
+3. After chipset enabling (all current board enables)
+
+Implementation note: All entries in board_pciid_enables get an
+additional phase parameter. Alternative variants (3 tables instead of 1)
+also have their downsides, and I chose table bloat over table
+multiplication).
+
+With this patch, it should be possible to whitelist supported laptops
+with a matching entry (phase P2) in board_pciid_enables which points to
+a function setting laptop_ok=1. (In case DMI is broken, matching might
+be a little bit more difficult, but it is still doable.)
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1293 | hailfinger | 2011-05-04 02:39:50 +0200 (Wed, 04 May 2011) | 6 lines
+
+Constify flashchips array.
+This moves 99.5% of the .data section to .rodata (which ends up in .text).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+
+------------------------------------------------------------------------
+r1292 | hailfinger | 2011-05-03 23:49:41 +0200 (Tue, 03 May 2011) | 15 lines
+
+Revert MMIO space writes on shutdown as needed.
+Reversible MMIO space writes now use rmmio_write*().
+Reversible PCI MMIO space writes now use pci_rmmio_write*().
+If a MMIO value needs to be queued for restore without writing it,
+use rmmio_val*().
+MMIO space writes which are one-shot (e.g. communication with some chip)
+should continue to use the permanent mmio_write* variants.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+David tested it successfully on some NM10/ICH7 platforms which switch
+between SPI and LPC targets (x86 BIOS ROM vs. EC firmware ROM).
+
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1291 | mkarcher | 2011-04-30 01:53:09 +0200 (Sat, 30 Apr 2011) | 4 lines
+
+improve output in case run_opcode fails
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1290 | mkarcher | 2011-04-30 00:11:36 +0200 (Sat, 30 Apr 2011) | 4 lines
+
+ichspi: Increase timeout to 60s for atomic operations
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1289 | hailfinger | 2011-04-27 16:34:08 +0200 (Wed, 27 Apr 2011) | 25 lines
+
+Add support for more than one Super I/O or EC per machine.
+
+flashrom currently only supports exactly one Super I/O or Embedded
+Controller, and this means quite a few notebooks and a small subset of
+desktop/server boards cannot be handled reliably and easily.
+Allow detection and initialization of up to 3 Super I/O and/or EC chips.
+
+WARNING! If a Super I/O or EC responds on multiple ports (0x2e and
+0x4e), the code will do the wrong thing (namely, initialize the hardware
+twice). I have no idea if we should handle such situations, and whether
+we should ignore the second chip with identical ID or not. Initializing
+the hardware twice for the IT87* family is _not_ a problem, but I don't
+know how well IT85* can handle it (and whether IT85* would listen at
+more than one port anyway).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Thanks to Thomas Schneider for testing on a board with ITE IT87* SPI.
+Test report (success) is here: http://paste.flashrom.org/view.php?id=379
+
+Thanks to David Hendricks for testing on a Google Cr-48 laptop with
+ITE IT85* EC SPI. Test report (success) is here:
+http://www.flashrom.org/pipermail/flashrom/2011-April/006275.html
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1288 | mkarcher | 2011-04-15 02:03:37 +0200 (Fri, 15 Apr 2011) | 16 lines
+
+Remove delays in JEDEC erase sequence
+
+It is extremely unlikely that a chip not requiring delays in probe does
+require them in erase. We observed unreliable erasing with a SST49LF004A
+with these delays, so remove them if the are not required.
+
+In review, I got the hint that "probe_jedec goes further by making that
+call conditional on nonzero delay". I decided to ignore that. For
+internal_delay, the small amount of clock cycles wasted for calling
+programmer_delay(0) is negligible compared to LPC cycle times. It might
+be an issue for 5 wasted bytes on the serial line in serprog. OTOH,
+flash erase is still slow compared to 6*5 bytes on a serial port at
+reasonable speed.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1287 | mkarcher | 2011-04-15 01:43:19 +0200 (Fri, 15 Apr 2011) | 13 lines
+
+Remove erase_chip_stm50flw0x0x
+
+As the comment indicates, that function is not a chip erase function
+at all, but a function calling a block eraser in a loop. So it adds
+no extra value to what we already have in the block_eraser
+infrastructure.
+
+Furthermore, that function assumes a uniform sector size layout, but
+is referenced from flash chip with non-uniform sector size layout, which
+is just wrong.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1286 | mkarcher | 2011-04-15 01:14:27 +0200 (Fri, 15 Apr 2011) | 12 lines
+
+Board enable for Foxconn 6150K8MD-8EKRSH
+
+Reported by: wickberg@student.chalmers.se
+
+flashrom -V: http://paste.flashrom.org/view.php?id=452
+lspci: http://paste.flashrom.org/view.php?id=453
+
+(note that the flashrom dump is with a foreign chip. That
+board is originally equipped with an PMC Pm49FL004.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+------------------------------------------------------------------------
+r1285 | hailfinger | 2011-04-02 13:47:21 +0200 (Sat, 02 Apr 2011) | 8 lines
+
+List AMD SB850 as supported (it has the same PCI ID as SB700).
+
+Success report at
+http://flashrom.org/pipermail/flashrom/2011-March/006072.html
+
+Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1284 | stepan | 2011-04-01 20:05:20 +0200 (Fri, 01 Apr 2011) | 5 lines
+
+coreboot table handling: make debug message msg_pdbg.
+
+Signed-off-by: Stefan Reinauer<stefan.reinauer@coreboot.org>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1283 | stepan | 2011-03-29 23:41:41 +0200 (Tue, 29 Mar 2011) | 6 lines
+
+Fix typo in chipset_enable.c
+
+Signed-off-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+Acked-by: Idwer Vollering <vidwer@gmail.com>                                                                             
+
+
+------------------------------------------------------------------------
+r1282 | stepan | 2011-03-18 23:00:15 +0100 (Fri, 18 Mar 2011) | 8 lines
+
+Update port of flashrom package to Mac OS X using DirectHW:
+http://www.coreboot.org/DirectHW
+
+Signed-off-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Paul Menzel <paulepanter@users.sourceforge.net>
+
+
+------------------------------------------------------------------------
+r1281 | hailfinger | 2011-03-17 01:10:25 +0100 (Thu, 17 Mar 2011) | 11 lines
+
+Proper error handling for ICH/VIA SPI:
+Use 16-bit values for bit masks in 16-bit registers.
+Check for SPI Cycle In Progress and wait up to 60 ms.
+Do not touch reserved bits.
+Reduce SPI cycle timeout from 60 s to 60 ms.
+Clear transaction errors caused by our own SPI accesses.
+Add better debugging in case the hardware misbehaves.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+
+------------------------------------------------------------------------
+r1280 | oxygene | 2011-03-08 08:17:44 +0100 (Tue, 08 Mar 2011) | 12 lines
+
+Fix and improve libpayload platform support
+
+- Fix various minor compile issues (eg. include necessary standard headers)
+- Fix compilation of libpayload code paths
+- Provide libpayload support in Makefile
+- Add make target "libflashrom.a" which links non-CLI code to static
+  library
+
+Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com>
+Tested-with-DOS-crosscompiler-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1279 | hailfinger | 2011-03-08 01:23:49 +0100 (Tue, 08 Mar 2011) | 18 lines
+
+Various IT85* cleanups and fixes.
+
+Fix a few typos.
+Change the EC memory region mapping name.
+Drop unused function parameter.
+Use mmio_writeb()/mmio_readb() to get reliable access to volatile memory
+locations instead of plain pointer access which is optimized away by gcc.
+Use own it85_* SPI high-level chip read/write functions instead of
+relying on unrelated ICH functions.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+David writes:
+I applied the patch against the Chromium OS branch and
+successfully tested read and write operations on a Cr48.
+
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1278 | hailfinger | 2011-03-08 01:09:11 +0100 (Tue, 08 Mar 2011) | 8 lines
+
+Fix compilation if CONFIG_INTERNAL=no.
+Fix compilation if everything except CONFIG_SATAMV is no.
+Do not compile in PCI support for wiki printing if no PCI devices are
+supported.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1277 | hailfinger | 2011-03-07 16:32:58 +0100 (Mon, 07 Mar 2011) | 5 lines
+
+Fix broken compilation caused by a typo in r1275.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1276 | hailfinger | 2011-03-07 11:59:06 +0100 (Mon, 07 Mar 2011) | 5 lines
+
+Mark Macronix MX25L1605D as fully tested.
+
+Signed-off-by: Sven Schnelle <svens@stackframe.org>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1275 | mkarcher | 2011-03-07 02:09:55 +0100 (Mon, 07 Mar 2011) | 6 lines
+
+SST39SF512 is tested
+
+flashrom -V -w: http://paste.flashrom.org/view.php?id=395
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1274 | hailfinger | 2011-03-07 02:08:09 +0100 (Mon, 07 Mar 2011) | 11 lines
+
+Simplify pcidev_init by killing the vendorid parameter which was pretty
+useless anyway since it was present in the pcidevs parameter as well.
+
+This also allows us to handle multiple programmers with different vendor
+IDs in the same driver.
+
+Fix compilation of flashrom with only the nicrealtek driver.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1273 | hailfinger | 2011-03-06 23:52:55 +0100 (Sun, 06 Mar 2011) | 11 lines
+
+Add a board enable for Asus P4P800-VM.
+
+Only list the memory controller PCI IDs because the only other subsystem
+mentioned is used by network and sound interfaces both of which can be
+turned off in BIOS.
+Tested on a board rev 1.85.
+
+Signed-off-by: Diego Elio Petten?\195?\178 <flameeyes@gmail.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+------------------------------------------------------------------------
+r1272 | hailfinger | 2011-03-06 23:26:23 +0100 (Sun, 06 Mar 2011) | 6 lines
+
+Mark PMC Pm49FL004, SST SST49LF002A/B, SST SST49LF004A/B and
+Winbond_W39V040FB as write tested.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1271 | hailfinger | 2011-03-06 23:16:30 +0100 (Sun, 06 Mar 2011) | 7 lines
+
+Add Gigabyte GA-MA780G-UD3H to mainboard support list.
+
+http://www.flashrom.org/pipermail/flashrom/2010-October/005117.html
+
+Signed-off-by: Bernhard Geier <geierb@geierb.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1270 | hailfinger | 2011-03-06 19:45:40 +0100 (Sun, 06 Mar 2011) | 7 lines
+
+Add support for ST M25PX16 and mark it as supported.
+Tests were performed with write and verify operations to 4 different
+M25PX16 chips with a Dediprog SF100.
+
+Signed-off-by: Carl Worth <carl.d.worth@intel.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1269 | hailfinger | 2011-03-06 19:31:11 +0100 (Sun, 06 Mar 2011) | 9 lines
+
+Mark SST49LF080A as fully tested.
+Mark EVGA nForce 780i board as supported.
+
+Full logs are here:
+http://www.flashrom.org/pipermail/flashrom/2011-January/005779.html
+
+Signed-off-by: Brandon Dowdy <brandonrd7@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1268 | mkarcher | 2011-03-06 18:58:05 +0100 (Sun, 06 Mar 2011) | 4 lines
+
+Add W39L040
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1267 | mkarcher | 2011-03-06 18:37:30 +0100 (Sun, 06 Mar 2011) | 4 lines
+
+Add coreboot IDs to make manual selection of HP xw9400 possible
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1266 | mkarcher | 2011-03-06 13:09:05 +0100 (Sun, 06 Mar 2011) | 15 lines
+
+Board-enable for GA-K8N51GMF
+
+Gigabyte is not really helpful with their PCI IDs for us, the subsystem
+IDs used just mean "gigabyte northbridge" and "gigabyte southbridge".
+We should investigate whether autodetection of this board is causing
+interference with other boards.
+
+real version 2: Extend list of PCI IDs for nvidia southbridges.
+
+flashrom -V: http://paste.flashrom.org/view.php?id=326
+lspic: http://paste.flashrom.org/view.php?id=328
+superiotool: http://paste.flashrom.org/view.php?id=329
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1265 | mkarcher | 2011-03-06 13:07:19 +0100 (Sun, 06 Mar 2011) | 11 lines
+
+Add HP e-Vectra P2706T
+
+Reported by: Michal Janke <jankeso@gmail.com>
+
+flashrom -V: http://paste.flashrom.org/view.php?id=370
+lspci: http://paste.flashrom.org/view.php?id=371
+superiotool: http://paste.flashrom.org/view.php?id=372 and
+  http://www.flashrom.org/pipermail/flashrom/2011-March/005878.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1264 | hailfinger | 2011-03-05 17:31:57 +0100 (Sat, 05 Mar 2011) | 9 lines
+
+I tested a few mainboards and flash chips.
+Successfully tested MSI MS-7596 (785GM-E51).
+Successfully tested ASRock 890GX Extreme3.
+Successfully tested Winbond W25x80.
+Mention which GIGABYTE GA-MA78G-DS3H board revision was tested.
+
+Signed-off-by: Yul Rottmann <yulrottmann@bitel.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1263 | hailfinger | 2011-03-01 00:58:15 +0100 (Tue, 01 Mar 2011) | 23 lines
+
+Update the ITE IT8500 EC support to match the current state of the
+flashrom-chromium tree.
+
+This code has been deployed and tested to work on the Cr-48.
+There are a few caveats, though:
+- The boot BIOS straps register must be modified to select LPC. This
+  can be done with the "select_bbs.sh" script (Install iotools at
+  http://code.google.com/p/iotools/ before using select_bbs).
+- It is very important to disable power management daemons before
+  running flashrom on this EC. I commented out the brute force method
+  we use in the Chromium OS branch that disables powerd, since IIRC
+  Carl-Daniel has a better approach in the works.
+- Due to dependencies which may be introduced by the OEM/ODM EC
+  firmware, the code is not guaranteed to work for anything other than
+  the Cr-48.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+
+Carl-Daniel comments:
+Code is not hooked up yet because probing needs to be sorted out.
+
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1262 | hailfinger | 2011-02-22 18:16:34 +0100 (Tue, 22 Feb 2011) | 12 lines
+
+Add generalized support for ITE IT8500/IT8502 embedded controllers.
+
+The patch was developed by Google.
+It was tested for IT8500E on a Chrome OS platform and may require
+modification depending on ODM/OEM customization and EC firmware version.
+This patch is not officially supported by ITE Tech Inc.
+
+Signed-off-by: Donald Huang <donald.huang@ite.com.tw>
+Signed-off-by: Yung-chieh Lo <yjlou@google.com>
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1261 | hailfinger | 2011-02-15 23:44:27 +0100 (Tue, 15 Feb 2011) | 14 lines
+
+Support 64-bit MEM BARs wherever possible.
+Add more sanity checks for BARs and abort if resources are unreachable.
+Undecoded resources are reported, but flashrom will proceed anyway just
+in case the BIOS screwed up the configuration.
+
+(The empty CardBus handler is intentional, according to the spec no BARs
+in PCI config space are used by CardBus.)
+
+Found while working on a driver for the Angelbird PCIe-based SSD which
+has 64-bit capable MEM BARs.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+
+------------------------------------------------------------------------
+r1260 | hailfinger | 2011-02-05 13:11:17 +0100 (Sat, 05 Feb 2011) | 8 lines
+
+Add support for AMD Am29LV001BB, Am29LV001BT, Am29LV002BB, Am29LV002BT,
+Am29LV004BB, Am29LV004BT, Am29LV008BB, Am29LV008BT
+
+Thanks to Mark Pustjens for testing the Am29LV001BB.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+
+------------------------------------------------------------------------
+r1259 | hailfinger | 2011-02-04 23:52:04 +0100 (Fri, 04 Feb 2011) | 6 lines
+
+Improve debugging for unaligned erase in the flash chip emulator.
+Fix out-of-bounds access for chip erase in the flash chip emulator.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1258 | hailfinger | 2011-02-04 22:37:59 +0100 (Fri, 04 Feb 2011) | 12 lines
+
+Support for Angelbird Wings PCIe SSD (solid-state drive).
+It uses a Marvell 88SX7042 SATA controller internally which has access
+to a separate flash chip hosting the option ROM.
+
+Thanks to Angelbird Ltd for sponsoring development of this driver!
+
+I expect the code to work for that SATA controller even if it is not
+part of the Angelbird SSD.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
+
+------------------------------------------------------------------------
+r1257 | stepan | 2011-01-28 10:00:15 +0100 (Fri, 28 Jan 2011) | 6 lines
+
+Support Dediprog LEDs on devices with 2 and 3 LEDs.
+
+Signed-off-by: Stefan Reinauer <reinauer@google.com>
+Acked-by: Mathias Krause <mathias.krause@secunet.com>
+
+
+------------------------------------------------------------------------
+r1256 | stepan | 2011-01-25 01:23:32 +0100 (Tue, 25 Jan 2011) | 10 lines
+
+flashrom: fix sparse warning: Unknown escape %
+
+This patch fixes wrong escaping of %.
+In print.c %%2b is correct instead of \%2b ("%%2b"=%2b=+)
+In board_enable.c %d is correct instead of \%d.
+
+Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+
+------------------------------------------------------------------------
+r1255 | stepan | 2011-01-24 20:15:51 +0100 (Mon, 24 Jan 2011) | 10 lines
+
+flashrom: fix sparse warning: Using plain integer as NULL pointer
+
+This patch fixes the "using plain integer as NULL pointer" warnings
+generated by running sparse on the flashrom source.
+
+Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
+Acked-by: Mathias Krause <mathias.krause@secunet.com>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+
+------------------------------------------------------------------------
+r1254 | stepan | 2011-01-20 22:05:15 +0100 (Thu, 20 Jan 2011) | 13 lines
+
+Secret knowledge is cool, but public knowledge is better.
+Implement all Dediprog commands found in USB traces, even if their
+purpose is not yet known.
+Annotate unknown commands with info about the call sequence they are
+embedded in and the firmware version of the log.
+
+Add a new shutdown command for firmware 5.x (of which Stefan thinks it's
+"switch the Pass light on" hence it is called late in the game)
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <reinauer@google.com>
+
+
+------------------------------------------------------------------------
+r1253 | stepan | 2011-01-19 07:21:54 +0100 (Wed, 19 Jan 2011) | 9 lines
+
+Don't print the local memory flash chip address on programmers that don't
+actually map the flash chip into local memory (like the dediprog) because
+the value does not make sense there.
+
+This version was reworked / rewritten by Mathias Krause to have less "impact"
+
+Signed-off-by: Stefan Reinauer <reinauer@google.com>
+Acked-by: Mathias Krause <mathias.krause@secunet.com>
+
+------------------------------------------------------------------------
+r1252 | krause | 2011-01-17 08:50:42 +0100 (Mon, 17 Jan 2011) | 10 lines
+
+This patch reduces the stack usage by declaring 'const' stack variables
+as 'static const' so they end up in the .rodata section instead of being
+copied from there to the stack for every invocation of the corresponding
+function. As a plus we end up in having a smaller binary as the "copy
+from .rodata to stack" code isn't emitted by the compiler any more
+(roughly -100 bytes).
+
+Signed-off-by: Mathias Krause <mathias.krause@secunet.com>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+------------------------------------------------------------------------
+r1251 | krause | 2011-01-17 08:45:54 +0100 (Mon, 17 Jan 2011) | 9 lines
+
+The AT26DF081A requires the Write Enable Latch (WLE) to be set for
+write/erase operations. Also bit 5 is the Erase/Program Error (EPE) bit,
+so has nothing to do with the block protection. Ignore it when testing
+for block protections.
+
+Signed-off-by: Mathias Krause <mathias.krause@secunet.com>
+Tested-by: Mathias Krause <mathias.krause@secunet.com>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+------------------------------------------------------------------------
+r1250 | krause | 2011-01-01 11:54:09 +0100 (Sat, 01 Jan 2011) | 8 lines
+
+Fix decoding of SB600 LPC ROM protection registers.
+
+The address part was using a bit of the size, the size was missing the
+upper bit, was off by 1023 bytes and included the protection bits.
+
+Signed-off-by: Mathias Krause <mathias.krause@secunet.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1249 | mkarcher | 2010-12-27 00:55:19 +0100 (Mon, 27 Dec 2010) | 9 lines
+
+compilation fix for djgpp
+
+This corrects a djgpp build error, seen with r1232 and later.
+
+pcidev.c:210: error: conflicting types for 'rpci_write_long'
+programmer.h:226: error: previous declaration of 'rpci_write_long' was here
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1248 | mkarcher | 2010-12-27 00:55:12 +0100 (Mon, 27 Dec 2010) | 7 lines
+
+enable unlocking (erasing/writing) W39V040FB chips
+
+Add code for the unlocking (erasing/writing) of Winbond W39V040FB
+chips, enabling erasing/writing this type of chip.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1247 | dhendrix | 2010-12-14 00:54:59 +0100 (Tue, 14 Dec 2010) | 4 lines
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+
+------------------------------------------------------------------------
+r1246 | hailfinger | 2010-12-06 14:05:44 +0100 (Mon, 06 Dec 2010) | 7 lines
+
+Simplify get_next_write in the partial write code.
+
+Suggested by Michael Karcher.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1245 | hailfinger | 2010-12-05 17:33:59 +0100 (Sun, 05 Dec 2010) | 18 lines
+
+Add support for Winbond W39V040FB and W39V040FC.
+
+Print lock status for all supported Winbond W39* chips:
+W39V040A, W39V040B, W39V040C, W39V040FA, W39V040FB, W39V040FC,
+W39V080A, W39V080FA, W39V080FA (dual mode).
+
+Fill in correct probe timing for Winbond W39V040C and W39V080FA.
+
+Please note that the W39V040B/W39V040FB pair has identical IDs,
+identical read/write/erase, but locking differs. Same applies to
+W39V040C/W39V040FC. This causes double detection on chipsets which
+support LPC and FWH, making flashing more difficult because the user
+has to select the correct chip. This is called the evil twin problem.
+A better evil twin handling (patch available) will resolve that problem.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1244 | hailfinger | 2010-12-05 16:14:44 +0100 (Sun, 05 Dec 2010) | 6 lines
+
+Clean up erase function checking.
+Update a few comments and messages to improve readability.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1243 | hailfinger | 2010-12-04 12:56:52 +0100 (Sat, 04 Dec 2010) | 5 lines
+
+Stop reading layout info when the max layout count has been reached.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1242 | hailfinger | 2010-12-04 04:26:40 +0100 (Sat, 04 Dec 2010) | 7 lines
+
+Annotate the following chips with probe timing:
+Am29F016D, Am29F040B, Am29LV040B, Am29LV081B, A29002B, A29002T, A29040B, 
+MX29F001B, MX29F001T, MX29F002B, MX29F002T, MX29LV040, M29F040B 
+
+Signed-off-by: David Borg <borg.db@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1241 | hailfinger | 2010-12-03 15:48:11 +0100 (Fri, 03 Dec 2010) | 28 lines
+
+Add support for the Open Graphics Project development card, OGD1, as a
+SPI flash programmer. The project is in the the process of designing
+and making a complete, open source, graphics card.
+More info at http://wiki.opengraphics.org.
+
+The first development card is a PCI add in card containing a couple of
+FPGAs and a couple of serial flash chips (amongst other things). The
+FPGAs are called XP10 and S3 (their part numbers). The XP10 contains
+its own flash and does not need to be programmed by flashrom - it
+ensures that the device can enumerate on the PCI bus without needing
+further configuration.
+
+The larger FPGA is the S3. This is configured from a large SPI flash
+(2 MBytes). The second SPI flash is used to store the VGA BIOS. It
+is smaller (128 KBytes). This patch adds support for programming either
+of the two SPI flash chips.
+
+The programmer device takes one configuration option which selects which
+of the two flash chips is accessed. This must be set to either "cprom"
+or "bprom". (The project refers to the two chips as "cprom" / "bprom",
+"s3" and "bios" are more readable alternatives).
+
+Add support for SST SST25VF010 (REMS).
+Mark SST SST25VF016B as tested for write.
+
+Signed-off-by: Mark Marshall <mark.marshall@csr.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1240 | hailfinger | 2010-12-02 22:59:42 +0100 (Thu, 02 Dec 2010) | 6 lines
+
+Avoid printing the chip locks if chip detection was forced because lock
+access may involve flash chip registers which will not be mapped.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1239 | uwe | 2010-12-02 22:57:42 +0100 (Thu, 02 Dec 2010) | 8 lines
+
+Add a board-enable for the MSI MS-6391 (845 Pro4).
+
+I found this via educated guessing and trial-and-error.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1238 | hailfinger | 2010-12-02 03:41:55 +0100 (Thu, 02 Dec 2010) | 5 lines
+
+Handle erase failure in partial write.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1237 | hailfinger | 2010-11-29 01:37:49 +0100 (Mon, 29 Nov 2010) | 6 lines
+
+Add support for Spansion S25FL004A, S25FL032A, and S25FL064A.
+Tested S25FL064A using a Bus Pirate.
+
+Signed-off-by: Rudy Host <segfault@committeeofdoom.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1236 | hailfinger | 2010-11-25 00:37:22 +0100 (Thu, 25 Nov 2010) | 7 lines
+
+Dump all VIA SPI registers like for ICH7.
+Handle BBAR on VIA.
+Handle SPI lockdown on VIA.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Rudolf Marek <r.marek@assembler.cz>
+
+------------------------------------------------------------------------
+r1235 | hailfinger | 2010-11-23 22:28:16 +0100 (Tue, 23 Nov 2010) | 12 lines
+
+Add chunked write ability to the Dediprog SF100 driver.
+
+Please note that the write speedup only applies to chips which have SPI
+page write (i.e. chips using spi_chip_write_256).
+
+This is a quick fix for write speed until I get around to implementing
+full bulk SPI write support.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Richard A. Smith  <richard@laptop.org>
+Acked-by: Mathias Krause <mathias.krause@secunet.com>
+
+------------------------------------------------------------------------
+r1234 | hailfinger | 2010-11-16 22:25:29 +0100 (Tue, 16 Nov 2010) | 16 lines
+
+Support bulk read on Dediprog SF100.
+Should result in native speed for plain read and erase.
+Should result in a measurable speedup for writes due to a fast verify.
+Packet size is 512 bytes. Depending on your USB hardware and the
+Dediprog firmware version, this may not work at all. That said, it
+worked on the hardware we tested.
+
+Add lots of error checking where it was missing before.
+
+Thanks to Richard A. Smith, Mathias Krause and David Hendricks for
+testing multiple iterations of this patch.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-By: Richard A. Smith <richard@laptop.org>
+Acked-By: Mathias Krause <mathias.krause@secunet.com>
+
+------------------------------------------------------------------------
+r1233 | hailfinger | 2010-11-16 18:21:58 +0100 (Tue, 16 Nov 2010) | 13 lines
+
+Read the to-be-verified area in one go.
+verify_range() and check_erased_range() check each page separately.
+While that may have seemed like a good idea back when the code was
+introduced, it has no benefits for any of the chips where we support
+write because all of them handle cross-page reads nicely.
+The only class of chips where this change could be a problem is chips
+with non power of two sector sizes which have gaps in the address space.
+We simply require their read functions to provide gap-free results
+and leave it at that.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-By: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1232 | hailfinger | 2010-11-10 16:25:18 +0100 (Wed, 10 Nov 2010) | 12 lines
+
+Revert PCI config space writes on shutdown.
+This means all chipset enables etc. will be undone on shutdown.
+Reversible PCI config space writes now use rpci_write_*().
+PCI config space writes which are one-shot (e.g. communication via
+config space) should continue to use the permanent pci_write_*
+variants.
+
+Extend the number of available register_shutdown slots to 32.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1231 | hailfinger | 2010-11-10 04:26:57 +0100 (Wed, 10 Nov 2010) | 9 lines
+
+Add support for the OpenMoko Neo1973/Neo FreeRunner debug board
+version 2 or 3 (vid:pid 1457:5118). The new type is called "openmoko".
+
+Information about the debug board can be found at
+http://wiki.openmoko.org/wiki/Debug_Board_v3
+
+Signed-off-by: Alex Badea <vamposdecampos@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1230 | hailfinger | 2010-11-10 04:22:39 +0100 (Wed, 10 Nov 2010) | 7 lines
+
+ft2232_spi ftdi_usb_open() is called with the constant FTDI_VID vendor
+ID. Fix it by using the programmer-type-dependent ft2232_vid variable,
+to allow programmers with other vendor IDs.
+
+Signed-off-by: Alex Badea <vamposdecampos@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1229 | hailfinger | 2010-11-10 04:18:41 +0100 (Wed, 10 Nov 2010) | 8 lines
+
+ft2232_spi: allow 5x clock divisor to be set at runtime.
+Check at init time whether the chip is a type 'H' (FT2232H or FT4232H).
+If not, omit the disable-divide-by-5 (0x8a) command which can confuse
+older chips.
+
+Signed-off-by: Alex Badea <vamposdecampos@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1228 | hailfinger | 2010-11-10 04:10:41 +0100 (Wed, 10 Nov 2010) | 8 lines
+
+Retry short reads in ft2232_spi.
+It is possible that ftdi_read_data() returns less data
+than requested. Catch this case and retry reading the rest
+of the buffer.
+
+Signed-off-by: Alex Badea <vamposdecampos@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1227 | hailfinger | 2010-11-10 00:30:43 +0100 (Wed, 10 Nov 2010) | 8 lines
+
+DediProg firmware version 5.1.5 of the SF-100 works just fine.
+Allow any firmware version from 2.x.y to 5.x.y.
+Handle errors for the initial USB command to catch -EPERM.
+
+Signed-off-by: Mathias Krause <mathias.krause@secunet.com>
+Acked-by: Patrick Georgi <patrick@georgi-clan.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1226 | hailfinger | 2010-11-09 23:00:31 +0100 (Tue, 09 Nov 2010) | 8 lines
+
+Support setting the Dediprog SF100 SPI voltage.
+Add a generic voltage parameter parser.
+Move tolower_string() from dummyflasher.c to flashrom.c to make it
+available everywhere.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+------------------------------------------------------------------------
+r1225 | hailfinger | 2010-11-05 15:51:59 +0100 (Fri, 05 Nov 2010) | 14 lines
+
+Avoid two memory leaks in doit() which were unproblematic for flashrom
+because flashrom terminates after finishing doit().
+Rename oldcontents to curconents in erase_and_write_block_helper().
+Unify the code for all granularities in get_next_write().
+Return write length from get_next_write() instead of filling it as
+referenced parameter.
+
+Thanks to Michael Karcher for pointing out the first two issues.
+Thanks to David Hendricks for pointing out the third issue and
+suggesting a way to unify that code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1224 | hailfinger | 2010-11-04 02:04:27 +0100 (Thu, 04 Nov 2010) | 27 lines
+
+This patch makes flashrom use real partial writes. If you write an image
+full of 0xff, flashrom will erase and detect that no write is needed. If
+you write an image which differs only in some parts from the current
+flash contents, flashrom will detect that and not touch unchanged areas.
+
+Fix a long-standing bug in need_erase() for 256 byte granularity as
+well.
+
+Nice side benefit: Detailed progress printing.
+S means skipped
+E means erased
+W means written
+
+Thanks to Andrew Morgan for testing countless iterations of this patch.
+Thanks to Richard A. Smith for testing on Dediprog SF100.
+Thanks to David Hendricks for the review and for creating a partial write
+torture test script and testing with it on Intel NM10 and AMD SB700 SPI.
+Thanks to Idwer Vollering for testing with Intel SPI NICs.
+Thanks to Rudolf Marek for testing on AMD SB710 and SiI SATA controllers.
+Thanks to Michael Karcher for the review.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+Acked-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1223 | hailfinger | 2010-11-02 04:12:51 +0100 (Tue, 02 Nov 2010) | 13 lines
+
+Change semantics of image building in the layout code.
+If a layout file was specified, all regions not mentioned in the layout
+file were taken from the new image instead of being preserved.
+If regions overlap, the non-included regions won.
+
+New behaviour:
+If a layout file is specified, only the regions explicitly requested for
+inclusion will be taken from the new image.
+If regions overlap, the included regions win.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1222 | hailfinger | 2010-11-02 04:03:38 +0100 (Tue, 02 Nov 2010) | 24 lines
+
+Add a line of output for each iteration of the torture test.
+This serves as a sort of progress indicator.
+
+The output looks like this::
+localhost ~ # FLASHROM="./flashrom" sh flashrom_partial_write_test.sh
+testing flashrom binary: ./flashrom
+Running test in /tmp/tmp.4xPejwaADU
+ffh pattern written in ff_4k.bin
+00h pattern written in 00_4k.bin
+Reading BIOS image
+Original image saved as bios.bin
+aligned region 0 test: passed
+...
+aligned region 15 test: passed
+unaligned region 0 test: passed
+...
+unaligned region 15 test: passed
+Result: PASSED
+restoring original bios image using system's flashrom
+test files remain in /tmp/tmp.4xPejwaADU
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1221 | hailfinger | 2010-11-02 01:16:27 +0100 (Tue, 02 Nov 2010) | 6 lines
+
+Use mktemp unconditionally for security reasons.
+Avoid non-portable seq.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1220 | hailfinger | 2010-11-01 23:07:04 +0100 (Mon, 01 Nov 2010) | 24 lines
+
+Add SPI flash emulation capability to the dummy programmer.
+
+You have to choose between
+- no emulation
+- ST M25P10.RES SPI flash chip (RES, page write)
+- SST SST25VF040.REMS SPI flash chip (REMS, byte write)
+- SST SST25VF032B SPI flash chip (RDID, AAI write)
+Example usage: flashrom -p dummy:emulate=SST25VF032B
+
+Flash image persistence is available as well.
+Example usage: flashrom -p dummy:image=dummy_simulator.rom
+
+Allow setting the max chunksize for page write with the dummy
+programmer.
+Example usage: flashrom -p dummy:spi_write_256_chunksize=5
+
+Flash emulation is compiled in by default. 
+
+This code helped me find and fix various bugs in the SPI write code
+as well as in the testsuite.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1219 | hailfinger | 2010-10-29 23:54:16 +0200 (Fri, 29 Oct 2010) | 8 lines
+
+Replace "$FLASHROM_PARAM" with ${FLASHROM_PARAM} in
+util/flashrom_partial_write_test.sh to avoid passing in quoted
+parameters which can cause problems especially if FLASHROM_PARAM is
+empty or contains spaces.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1218 | hailfinger | 2010-10-29 22:17:41 +0200 (Fri, 29 Oct 2010) | 8 lines
+
+flashrom torture test script.
+Focus is on partial write and layout functionality.
+
+Minor modifications by Carl-Daniel Hailfinger.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1217 | hailfinger | 2010-10-28 00:07:11 +0200 (Thu, 28 Oct 2010) | 13 lines
+
+Fix internal offset calculations for SPI BYTE PROGRAM and SPI AAI PROGRAM.
+The bug was invisible so far because we always started at offset 0. The
+pending partial write patch uses nonzero start offsets and trips over
+this bug.
+
+Clarify a few comments in IT87 SPI.
+
+Thanks to Idwer Vollering for reporting write breakage with my latest
+partial write patch. This should fix the underlying problem.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1216 | hailfinger | 2010-10-20 23:13:19 +0200 (Wed, 20 Oct 2010) | 16 lines
+
+Add a reset to probe_jedec before we read the Chip's IDs.
+
+Previous probes might have had too short delays for entering ID mode,
+so the chip may still be in the process of entering the ID mode. Due to
+that, an additional delay before the reset makes sense.
+Add FEATURE_RESET_MASK to deal cleanly with those feature bits.
+
+Maciej Pijanka tested the patch and it fixes probing for him with some
+old Atmel chips.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Anders Juel Jensen <andersjjensen@gmail.com>
+Tested-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com> 
+
+------------------------------------------------------------------------
+r1215 | hailfinger | 2010-10-20 00:06:20 +0200 (Wed, 20 Oct 2010) | 18 lines
+
+Always read the flash chip before writing. This will allow flashrom to
+skip erase of already-erased blocks and to skip write of blocks which
+already have the wanted contents.
+
+Avoid emergency messages by checking if the chip contents after a failed
+write operation (erase/write) are unchanged.
+
+Keep the emergency messages after a failed pure erase. That part is
+debatable because if someone wants erase, he pretty sure doesn't care
+about the flash contents anymore.
+
+Please note that this introduces additional overhead of a full chip read
+before write. This is frowned upon by people with slow programmers.
+A followup patch will make this configurable.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coreboot.org>
+
+------------------------------------------------------------------------
+r1214 | uwe | 2010-10-19 00:32:03 +0200 (Tue, 19 Oct 2010) | 12 lines
+
+Fix board name, EP-8NPAI should have been EP-8NPA7I (trivial).
+
+Details, lspci/superiotool/flashrom logs:
+
+  http://www.flashrom.org/pipermail/flashrom/2010-October/005160.html
+
+Also add the vendor website URL for this board.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1213 | uwe | 2010-10-16 01:02:15 +0200 (Sat, 16 Oct 2010) | 7 lines
+
+Add a board enable for the EPoX EP-8NPA7I board.
+Also, spelling correction.
+
+Signed-off-by: Jonathan Kollasch <jakllsch@kollasch.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1212 | hailfinger | 2010-10-15 02:01:14 +0200 (Fri, 15 Oct 2010) | 9 lines
+
+doit() is the monster function we split off from main() when we created
+cli_classic() and tried to introduce some abstraction. doit() is a
+poster child of WTFs on an astronomic scale.
+
+Make doit() less bad by factoring out self-contained code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1211 | hailfinger | 2010-10-14 00:26:56 +0200 (Thu, 14 Oct 2010) | 12 lines
+
+Switch all flash chips to partial write.
+The inner write functions which handle partial write are renamed to the
+original name of their wrappers. The write wrappers are removed.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+Tested-by: Andrew Morgan <ziltro@ziltro.com>
+Tested-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Tested-by: Sean Nelson <audiohacked@gmail.com> 
+Acked-by: Sean Nelson <audiohacked@gmail.com> 
+
+------------------------------------------------------------------------
+r1210 | hailfinger | 2010-10-13 23:49:30 +0200 (Wed, 13 Oct 2010) | 17 lines
+
+Refactor remaining write wrappers.
+
+Kill duplicated code.
+
+Annotate write functions with their chunk size.
+
+Mark Fujitsu MBM29F400BC and ST M29F400BB as untested because their
+write code no longer uses a broken layout.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+Tested-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+Tested-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Tested-by: Sean Nelson <audiohacked@gmail.com> 
+Acked-by: Sean Nelson <audiohacked@gmail.com> 
+
+------------------------------------------------------------------------
+r1209 | hailfinger | 2010-10-10 18:10:49 +0200 (Sun, 10 Oct 2010) | 6 lines
+
+Simplify calls to inner write functions. No behavioural changes, just
+equivalence transformations.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1208 | hailfinger | 2010-10-10 16:02:27 +0200 (Sun, 10 Oct 2010) | 37 lines
+
+The currently used write functions (wrappers) all use helpers which
+perform the actual write (inner functions).
+
+The signature of the write wrappers is:
+int write_chip(struct flashchip *flash, uint8_t * buf);
+
+The signature of the inner write functions varied a lot. This patch
+changes them to:
+int write_part(struct flashchip *flash, uint8_t *src, int start, int len);
+
+Did you know that flashrom has only 8 inner write functions for all
+flash chips?
+write_page_write_jedec_common
+write_sector_jedec_common
+write_sector_28sf040
+spi_chip_write_256_new
+spi_chip_write_1_new
+spi_aai_write_new
+write_page_82802ab
+write_page_m29f400bt
+
+Export all inner write functions.
+
+Change the function signature of wait_82802ab to eliminate single-use
+variables.
+
+Remove an error message in write_page_m29f400bt which was printed for
+every byte written regardless of success.
+
+Add sharplhf00l04.c to the list of flash chip drivers in the Makefile.
+While the functions in there are unused, I suspect we will need them
+later, and by hooking the file up we ensure that compilation won't
+break.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1207 | hailfinger | 2010-10-08 22:29:57 +0200 (Fri, 08 Oct 2010) | 8 lines
+
+Remove progress printing from individual flash chip drivers.
+
+Progress printing should be handled in the generic code, and will end up
+there once partial write is possible.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1206 | hailfinger | 2010-10-08 20:52:29 +0200 (Fri, 08 Oct 2010) | 13 lines
+
+flashrom had an implicit erase-on-write for most flash chip and
+programmer drivers, but it was not entirely consistent. Some drivers had
+their own hand-rolled partial update functionality which made handling
+partial updates from generic code impossible.
+
+Move implicit erase out of chip drivers, and kill some dead erase
+functions at the same time.
+A full chip erase is now performed in the generic code for all flash
+chips on write, and after that the whole chip is written.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1204 | hailfinger | 2010-10-08 18:31:43 +0200 (Fri, 08 Oct 2010) | 5 lines
+
+Increase flashrom release number to 0.9.3.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1203 | hailfinger | 2010-10-08 14:40:09 +0200 (Fri, 08 Oct 2010) | 12 lines
+
+CONFIG_BITBANG_SPI was not selected if CONFIG_NICINTEL_SPI was on by
+default.
+Wiki output was missing all flash chips if CONFIG_INTERNAL was not
+selected.
+Use correct type for toupper()/tolower()/isspace() functions.
+Specify software requirements in a generic way.
+Non-x86 compilation does not work with the default programmer set, so
+list the make parameters which result in a working build.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1202 | hailfinger | 2010-10-08 13:03:02 +0200 (Fri, 08 Oct 2010) | 8 lines
+
+A lot of messages sent to flashrom@flashrom.org just have "flashrom -V"
+as the subject. 
+Ask people to include more information in the subject line to make life
+easier for developers/supporters.
+
+Signed-off-by: Paul Menzel <paulepanter@users.sourceforge.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1201 | hailfinger | 2010-10-08 02:37:55 +0200 (Fri, 08 Oct 2010) | 7 lines
+
+SPI write status register (WRSR) may take longer than 100 ms, and it
+makes sense to poll for completion in 10 ms steps until 5 s are over.
+This patch complements r1115.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Joshua Roys <roysjosh@gmail.com>
+
+------------------------------------------------------------------------
+r1200 | hailfinger | 2010-10-08 00:21:45 +0200 (Fri, 08 Oct 2010) | 8 lines
+
+List the devices for all supported programmers in "flashrom -L" output.
+Fix PCI device ID printing.
+Remove personal e-mail addresses from the man page, point people to
+flashrom@flashrom.org instead.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1199 | hailfinger | 2010-10-07 01:48:34 +0200 (Thu, 07 Oct 2010) | 8 lines
+
+flashrom -L output did not contain a list of programmers nor were all
+programmers listed.
+Fix it and mention at least the name of each programmer.
+Wiki output is unchanged, and will need separate fixups.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1198 | hailfinger | 2010-10-07 01:16:10 +0200 (Thu, 07 Oct 2010) | 7 lines
+
+The Direct I/O library for Mac OS X is now called DirectHW to make sure
+people can find it via an internet search. DirectIO was a generic name
+for a concept and thus not a good distinguisher for a library.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r1197 | hailfinger | 2010-10-07 01:03:21 +0200 (Thu, 07 Oct 2010) | 6 lines
+
+Update the author list in the man page.
+Update programmer parameter documentation.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1196 | stepan | 2010-10-06 04:56:44 +0200 (Wed, 06 Oct 2010) | 6 lines
+
+Remove duplicate includes from the code.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1195 | hailfinger | 2010-10-06 01:21:51 +0200 (Wed, 06 Oct 2010) | 6 lines
+
+DJGPP: Avoid leaking memory on lowmem mapping error.
+Add a clarifying comment about why low memory is never unmapped.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Rudolf Marek <r.marek@assembler.cz>
+
+------------------------------------------------------------------------
+r1194 | hailfinger | 2010-10-06 00:29:08 +0200 (Wed, 06 Oct 2010) | 9 lines
+
+Use AAI write for SST SST25VF032B.
+Speedup from 228 to 113 seconds.
+
+Use page (256 byte) write for SST SST25VF064C.
+Speedup from 3091 to 123 seconds.
+
+Signed-off-by: Helge Wagner <helge.wagner@ge.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1193 | hailfinger | 2010-10-06 00:06:05 +0200 (Wed, 06 Oct 2010) | 5 lines
+
+Implement on-the-fly reprogramming of the ICH SPI OPCODE table.
+
+Signed-off-by: Helge Wagner <helge.wagner@ge.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1192 | uwe | 2010-10-05 23:48:43 +0200 (Tue, 05 Oct 2010) | 13 lines
+
+Add a board-enable for the ASRock K7S41, chipset-enable for SiS 741.
+
+This also adds (and marks as tested) a chipset-enable for the SiS 741.
+
+All operations successfully tested on hardware.
+
+lspci/superiotool:
+  http://www.flashrom.org/pipermail/flashrom/2010-September/004710.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1191 | mhm | 2010-10-05 23:32:29 +0200 (Tue, 05 Oct 2010) | 24 lines
+
+Add board enable for Dell OptiPlex GX1 and mark Intel 28F002BC/BL/BV/BX-T
+as tested.
+
+Match on ethernet and north bridge.
+
+This is tested on an OptiPlex GX1 400L+ but will probably work for
+the whole GX1 series as they all share the same vendor BIOS.
+
+lspci/flashrom output
+http://www.flashrom.org/pipermail/flashrom/2010-July/004042.html
+
+lspci output (OptiPlex GX1 unknown model)
+http://www.coreboot.org/pipermail/coreboot/2010-May/058040.html
+
+superiotool output (OptiPlex GX1 266L+)
+http://www.flashrom.org/pipermail/flashrom/2009-July/000207.html
+
+lspci/dmidecode output (OptiPlex GX1 266L+)
+http://www.coreboot.org/pipermail/coreboot/2009-July/050958.html
+
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1190 | uwe | 2010-10-05 23:21:09 +0200 (Tue, 05 Oct 2010) | 12 lines
+
+Quickfix for broken writes on FT2232H based programmers.
+
+Not sure if this is the final/correct fix, but for now it definately
+fixes writes on FT2232H hardware. I have tested this on both, the
+DLP Design DLP-USB1232H, and the openbiosprog-spi hardware.
+
+Thanks to Joshua Roys <roysjosh@gmail.com> for the hint on IRC.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1189 | mhm | 2010-10-05 22:28:36 +0200 (Tue, 05 Oct 2010) | 54 lines
+
+Make sure all chip variants are present in .name strings in flashchips.c
+
+Strip package prefix in constant names (everything before "28F").
+
+Prefix every constant name with INTEL_
+
+Sort intel chip constants by ID.
+
+Rename the following constants to their "canonical" name:
+
+P28F400BT (0x70  -> INTEL_28F400T (28F400BV/BX/CE/CV-T)
+P28F400BB (0x71) -> INTEL_28F400B (28F400BV/BX/CE/CV-B)
+P28F004BT (0x78) -> INTEL_28F004T (28F004B5/BE/BV/BX-T)
+P28F004BB (0x79) -> INTEL_28F004B (28F004B5/BE/BV/BX-B)
+E_28F008S5 (0xA6) -> INTEL_28F008S3 (28F008S3/S5/SC)
+E_28F004S5 (0xA7) -> INTEL_28F004S3 (28F008S3/S5/SC)
+P28F001BXT (0x94) -> INTEL_28F001T (28F001BN/BX-T)
+P28F001BXB (0x95) -> INTEL_28F001B (28F001BN/BX-B)
+E_28F016S5 (0xAA) -> INTEL_28F016S3 (28F016S3/S5/SC)
+
+Add chip IDs for the following chips:
+
+28F320J5
+28F640J5
+28F320J3
+28F640J3
+28F128J3
+28F256J3
+28F200BL/BV/BX/CV-T
+28F200BL/BV/BX/CV-B
+28F002BL/BV/BX-B
+28F008BE/BV-T
+28F008BE/BV-B
+28F800B5/BV/CE/CV-T
+28F800B5/BV/CE/CV-B
+28F016SA/SV
+28F008SA
+28F008S3/S5/SC
+28F008S3/S5/SC
+28F016XS
+28F010
+28F512
+28F256A
+28F020
+28F016B3-T
+28F016B3-B
+28F008B3-T
+28F008B3-B
+28F004B3-T
+28F004B3-B
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1188 | hailfinger | 2010-10-05 21:19:48 +0200 (Tue, 05 Oct 2010) | 13 lines
+
+Speed up RayeR SPIPGM driver in flashrom by a factor of 2.
+
+Allow specification of an alternate base address with
+flashrom -p rayer_spi:iobase=0x278
+Any base address is allowed as long as it is nonzero, below 65536 and a
+multiple of four.
+
+Read speed is now on par with original spipgm.exe.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Martin Rehak <rayer@seznam.cz>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1187 | mkarcher | 2010-10-05 19:29:35 +0200 (Tue, 05 Oct 2010) | 11 lines
+
+Board enable for GA-6IEM
+
+Reported by Konstantin <hc@comp.susu.ac.ru>
+lspci (superiotool missing, doesn't matter for this patch)
+ http://www.coreboot.org/pipermail/flashrom/2010-September/004609.html
+DMI is needed, as there are no usefull PCI IDs.
+
+(no test of that board yet, thus marked as untested)
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1186 | hailfinger | 2010-10-05 15:31:12 +0200 (Tue, 05 Oct 2010) | 6 lines
+
+Update README to list all the needed rpm files for DOS cross-compilation
+and update the download location of cwsdpmi.
+
+Signed-off-by: Idwer Vollering <vidwer+flashrom@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1185 | hailfinger | 2010-10-05 13:16:14 +0200 (Tue, 05 Oct 2010) | 6 lines
+
+Add Intel 82571EB and 82572EI Gigabit NICs to the supported list.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Tested-by: Iain Paton <selsinork@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1184 | oxygene | 2010-09-30 19:03:32 +0200 (Thu, 30 Sep 2010) | 8 lines
+
+Add support for building flashrom against libpayload.
+This doesn't include changes to the frontend which must be
+done separately, so this won't work out of the box.
+This code was tested on hardware.
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1183 | hailfinger | 2010-09-30 01:37:24 +0200 (Thu, 30 Sep 2010) | 5 lines
+
+Support for Loongson-2F (MIPS) flashing.
+
+Signed-off-by: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1182 | hailfinger | 2010-09-26 23:43:53 +0200 (Sun, 26 Sep 2010) | 9 lines
+
+Half a dozen hardcoded strcmp() don't make sense if we need a
+chassis-type list anyway once we merge the internal DMI decoder.
+Provide and array of the most interesting chassis types and annotate
+them with laptop/non-laptop status.
+Match the dmidecode chassis type against the strings in the array.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1181 | hailfinger | 2010-09-26 00:53:44 +0200 (Sun, 26 Sep 2010) | 13 lines
+
+Implement libpayload support and improve life for DOS
+based flashrom, too:
+
+Change the physmap* behaviour to use (void*)-1 as error code instead
+of NULL. That way, 1:1 mapped memory can be supported properly
+because (void*)0 is not a magic pointer anymore.
+(void*)-1 on the other hand is a rather unlikely memory offset, so that
+should be safe.
+  
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1180 | uwe | 2010-09-20 19:23:38 +0200 (Mon, 20 Sep 2010) | 14 lines
+
+The variable 'ret' is unused when compiling on BigEndian architecture.
+
+This produces an "unused variable" message, which might be treated as error
+if -Werror was passed to compiler.
+
+With this patch I was able to compile flashrom cleanly on ppc and ppc64:
+
+http://koji.fedoraproject.org/koji/taskinfo?taskID=2472482
+http://koji.fedoraproject.org/koji/taskinfo?taskID=2472484
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1179 | mhm | 2010-09-19 01:42:36 +0200 (Sun, 19 Sep 2010) | 18 lines
+
+Add chip IDs for Alliance Semiconductor flash chips.
+
+Cross-checked with UniFlash 1.40 source, chip datasheets and
+EZoFlash's chip database (http://www.ezoflash.com/chip_database.php).
+
+Datasheets:
+http://www.ezoflash.com/datasheets/flash/Alliance/AS29F002.pdf
+http://www.alsc.com/pdf/flash.pdf/as29f010.pdf
+http://www.alsc.com/pdf/flash.pdf/as29f040.pdf
+http://www.alsc.com/pdf/flash.pdf/as29f200.pdf
+http://www.ezoflash.com/datasheets/flash/Alliance/AS29LV160.pdf
+http://www.ezoflash.com/datasheets/flash/Alliance/AS29LV400.pdf
+http://www.ezoflash.com/datasheets/flash/Alliance/AS29LV800.pdf
+
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1178 | hailfinger | 2010-09-17 00:34:25 +0200 (Fri, 17 Sep 2010) | 15 lines
+
+Thanks to Johannes Sj?\195?\182lund for reporting that the Bus Pirate init could
+not deal with a Bus Pirate which is already in binary Bitbang mode. This
+is caused by a combination of the slowness of the Bus Pirate, the
+slowness of USB and a fast serial port flush routine which just flushes
+the buffer contents and does not wait until data arrival stops.
+
+Make the Bus Pirate init more robust by running the flush command 10
+times with 1.5 ms delay in between.
+
+This code development was sponsored by Mattias Mattsson. Thanks!
+Tested a few dozen times, should work reliably.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Mattias Mattsson <vitplister@gmail.com>
+
+------------------------------------------------------------------------
+r1177 | mhm | 2010-09-17 00:09:18 +0200 (Fri, 17 Sep 2010) | 15 lines
+
+Add board enable for Elitegroup GeForce6100SM-M
+
+Match on Memory Controller/LPC Bridge.
+
+lspci/superiotool output:
+http://www.coreboot.org/pipermail/flashrom/2010-September/004829.html
+
+Test report:
+http://www.coreboot.org/pipermail/flashrom/2010-September/004835.html
+
+
+Tested-by: Andrew Cleveland <evil.saltine@gmail.com>
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1176 | mhm | 2010-09-16 02:51:51 +0200 (Thu, 16 Sep 2010) | 21 lines
+
+Add chip definitions for the folowing chips:
+
+Bright BM29F040
+Hyundai HY29F040A
+Macronix MX29F040
+
+Also add chip IDs for
+Bright BM29F400T/B
+
+Datasheets:
+http://www.ezoflash.com/datasheets/flash/Winbond/BM29F040.pdf
+http://www.ezoflash.com/datasheets/flash/Hyundai/HY29F040A.pdf
+http://www.ezoflash.com/datasheets/flash/Macronix/MX29F040.pdf
+http://www.ezoflash.com/datasheets/flash/Winbond/BM29F400T_B.pdf
+
+Bright BM29F040 probe/read test report:
+http://www.flashrom.org/pipermail/flashrom/2010-September/004805.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Mattias Mattsson <vitplister@gmail.com>
+
+------------------------------------------------------------------------
+r1175 | mhm | 2010-09-16 01:31:03 +0200 (Thu, 16 Sep 2010) | 22 lines
+
+This patch changes the prefix of chip constant #defines in the following way:
+
+AM_* -> AMD_AM*
+AT_* -> ATMEL_AT*
+EN_* -> EON_EN*
+HY_* -> HYUNDAI_HY*
+MBM* -> FUJITSU_MBM*
+MX_ID -> MACRONIX_ID
+MX_* -> MACRONIX_MX*
+PMC_* -> PMC_PM*
+SST_* -> SST_SST*
+
+It leaves the Intel #defines alone because there is another pending
+patch for that:
+http://patchwork.coreboot.org/patch/1937/
+
+Some background discussion here:
+http://www.flashrom.org/pipermail/flashrom/2010-July/004059.html
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1174 | hailfinger | 2010-09-15 16:47:56 +0200 (Wed, 15 Sep 2010) | 7 lines
+
+Add chipset enable for Broadcom OSB4.
+
+No docs available.
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1173 | hailfinger | 2010-09-15 14:02:07 +0200 (Wed, 15 Sep 2010) | 21 lines
+
+AMD SB700 and later have an integrated microcontroller (IMC) which runs
+from shared flash. The IMC will happily issue reads while we write,
+issue writes while we read, and generally cause lots of havoc due to the
+concurrent accesses it performs while flashrom is running.
+A failing or corrupted read can be detected since r1145, and the worst
+case is that the read aborts and the user has to retry.
+A failing write is much more serious. It can be detected since r1145,
+but if the SPI interface locks up, we can't continue writing nor can we
+read the current chip contents.
+
+If the IMC is inactive, there is no reason to worry. If the IMC is
+active, flashrom will refuse to erase/write the chip with this patch.
+
+The correct fix would be to stop the IMC during flashing, but apparently
+the relevant registers are undocumented, so we take the safe route for
+now until someone from AMD can give us more info.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Matthias Kretz <kretz@kde.org>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1172 | hailfinger | 2010-09-15 12:20:16 +0200 (Wed, 15 Sep 2010) | 21 lines
+
+Delay between probe and subsequent operations.
+
+Some flash chips need time to exit ID mode, and while we take care of
+correct timing for the matching probe, subsequent probes may have
+totally different timing, and that can lead to garbage responses from
+the flash chip during the first accesses after the probe sequence is
+done.
+Delay 100 ms between the last probe and any subsequent operation.
+To ensure maximum correctness, we would have to reset the chip first in
+case the last probe function left the chip in an undefined (non-read)
+state. That will be possible once struct flashchip has a .reset
+function.
+
+This fixes unstable erase/read/write for some flahs chips on nic3com and
+possible other use cases as well.
+
+Thanks to Maciej Pijanka for reporting the issue and testing patches.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1171 | hailfinger | 2010-09-15 02:17:37 +0200 (Wed, 15 Sep 2010) | 23 lines
+
+SPI bitbanging: request/release bus.
+
+SPI bitbanging on devices which speak SPI natively has a dual-use
+problem: We need to shut down normal SPI operations to do the bitbanging
+ourselves. Once we're done, it makes a lot of sense to reenable "normal"
+SPI operations again. Add request_bus/release_bus functions to struct
+bitbang_spi_master.
+Add a bitbang shutdown function (not used yet).
+Change MCP SPI and Intel NIC SPI to use the new request/release bus
+infrastructure.
+Cosmetic changes to a few error messages (80 column limit).
+
+There are multiple possible strategies for bus request/release:
+- Request at the start of a SPI command, release immediately afterwards.
+- Request at the start of a SPI multicommand, release once all commands
+of the multicommand are done.
+- Request on programmer init, release on shutdown.
+Each strategy has its own advantages. For now, we will stay with the
+first strategy which worked fine so far.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1170 | hailfinger | 2010-09-15 02:13:02 +0200 (Wed, 15 Sep 2010) | 22 lines
+
+Honor ICH SPI address window for reads.
+
+ICH SPI has the ability to restrict SPI read/write accesses to a given
+address range. The low end of the range is configurable by the BIOS (and
+by flashrom if the BIOS didn't lock down the flash interface), the high
+end of the range is 0xffffff (2^24-1).
+This patch checks for an address range restriction and uses the low end
+of the allowed range as base for SPI reads. A similar workaround for
+REMS/RES opcodes has been committed in r500.
+
+This fixes read on the Intel D945GCLF mainboard where the stock BIOS
+enforces a restricted address range.
+Please note that writes need the same fix, but for architectural reasons
+that fix will be merged once partial write is available.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Tested by David Hendricks on the Intel D945GCLF mainboard, results at
+http://paste.flashrom.org/view.php?id=79
+
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1169 | uwe | 2010-09-15 02:03:53 +0200 (Wed, 15 Sep 2010) | 6 lines
+
+Add missing GIGABYTE GA-7DXR entry, should have been in r1166.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1168 | mhm | 2010-09-15 01:56:56 +0200 (Wed, 15 Sep 2010) | 56 lines
+
+Rename constants
+W_nnnn -> WINBOND_Wnnnn
+W_25nnn -> WINBOND_NEX_W25nnn
+
+Kill incorrect ASD chip and vendor id.
+
+Group Winbond SPI and parallel chips separately (they have different
+vendor IDs).
+
+Change constant names to the "canonical" chip name for the following
+ids:
+
+W_29C020C (0x45)
+ -> WINBOND_W29C020 (Same as W29C020C, W29C022 and ASD AE29F2008)
+
+W_29C040P (0x46)
+ -> WINBOND_W29C040 ("P" is for package type [32-pin PLCC], irrelevant)
+
+W_29C011 + W_29EE011 (0xC1)
+ -> WINBOND_W29C010 (Same as W29C010M, W29C011A, W29EE011, W29EE012,
+    and ASD AE29F1008)
+
+
+List all chip variants in the .name strings in flashchips.c
+
+
+Have two identical entries for Winbond
+W29C010(M)/W29C011A/W29EE011/W29EE012 but with different probe functions
+in flashchips.c as sometimes (for newer revisions of these chips?) the
+standard jedec probe seems to work. E.g. see test report here:
+http://patchwork.coreboot.org/patch/1476/
+
+
+Also add ids for the following Winbond chips:
+W25Q40
+W25Q128
+W19B160BB
+W19B160BT
+W19B320SB/W19L320SB
+W19B320ST/W19L320ST
+W19B322MB
+W19B322MT
+W19B323MB
+W19B323MT
+W19B324MB
+W19B324MT
+W29C512A/W29EE512
+W39L010
+W39L040A
+W39L512
+W49F002/W49F002B
+
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1167 | uwe | 2010-09-15 01:20:35 +0200 (Wed, 15 Sep 2010) | 14 lines
+
+Board-enable for the ASUS A7V333.
+
+The board-enable is the same as for the ASUS A7V8X, i.e., it raises
+GP51 on the ITE IT8703F. I verified using a multimeter that this
+will raise both, WE# and TBL# on the flash chip.
+
+All operations successfully tested on hardware.
+
+Also renamed board_asus_a7v8x() to it8703f_gpio51_raise().
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Joshua Roys <roysjosh@gmail.com>
+
+
+------------------------------------------------------------------------
+r1166 | uwe | 2010-09-15 00:59:39 +0200 (Wed, 15 Sep 2010) | 36 lines
+
+Another round of board/chip status updates.
+
+Mark the following boards as tested:
+
+ - Intel Foxhollow (reported by Jason Shriver <J.Shriver@F5.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004768.html
+
+ - Intel Greencity (reported by Jason Shriver <J.Shriver@F5.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004768.html
+
+ - Tyan S2915-E (Thunder n6650W) (reported by Axel Bergerhoff
+   <axelbergerhoff@compuserve.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004560.html
+
+ - ASUS Z8NA-D6C (reported by John Wells <jb@sourceillustrated.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004737.html
+
+ - GIGABYTE GA-7DXR (reported by Uwe Hermann <uwe@hermann-uwe.de>)
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004712.html
+
+ - MSI MS-7211 (PM8M3-V) (reported by Shahar Or <mightyiampresence@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004612.html
+
+ - MSI MS-6787 (P4MAM-V/P4MAM-L) (reported by Swift Geek <swiftgeek@gmail.com>)
+   Board-enable now marked as tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004687.html
+
+Chips:
+
+ - SST SST25VF016B (reported by Warren Turkal <wt@penguintechs.org>)
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004716.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1165 | uwe | 2010-09-14 15:16:01 +0200 (Tue, 14 Sep 2010) | 7 lines
+
+Add support for ST M25PX32 and M25PX64 flash chips. Probe, read, erase and
+write have been tested and all are functional.
+
+Signed-off-by: Jason Shriver <j.shriver@f5.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1164 | hailfinger | 2010-09-14 03:29:49 +0200 (Tue, 14 Sep 2010) | 9 lines
+
+Use caching for Nvidia MCP SPI GPIO accesses.
+Reduce clock delay to zero.
+
+Tests show more than 2x speedup.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Andrew Morgan <ziltro@ziltro.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1163 | uwe | 2010-09-14 01:00:57 +0200 (Tue, 14 Sep 2010) | 7 lines
+
+Add support for the abit BM6 board.
+
+Signed-off-by: Tim ter Laak <timl@scintilla.utwente.nl>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1162 | uwe | 2010-09-13 21:59:28 +0200 (Mon, 13 Sep 2010) | 6 lines
+
+Add support for the Macronix MX251635E chip.
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1161 | mhm | 2010-09-13 21:39:25 +0200 (Mon, 13 Sep 2010) | 27 lines
+
+Add board enable for ASUS P4SC-E.
+
+I does this by setting bits 3..2 of register 0x24 on the ITE IT8707F,
+while keeping bit 3 of register 0x23 set while manipulating the first
+register.
+
+AFAIK, there is no public datasheet available for this super i/o chip, but
+the above is how the vendor BIOS does it. Also, registers 0x23 and 0x24 seem
+to have the same meaning as on the ITE IT8710F.
+
+Matching on NB/SB.
+
+Tested on a P4SC-E with SST 39SF020A flash. Probe, read, erase, write
+all work.
+
+lspci/superio output:
+http://www.flashrom.org/pipermail/flashrom/2010-July/004090.html
+
+flashrom output:
+http://www.flashrom.org/pipermail/flashrom/2010-August/004566.html
+
+Many thanks to Reinder de Haan for help with reverse engineering this!
+
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1160 | mhm | 2010-09-13 20:22:36 +0200 (Mon, 13 Sep 2010) | 18 lines
+
+Board enable for MS-6163 Pro (MS-6163 rev:2)
+
+Matching on NB/SB. Probe, read, erase and write all work.
+
+lspci/superiotool output:
+http://www.flashrom.org/pipermail/flashrom/2010-August/004461.html
+
+I believe that this board enable also works for MSI BX Master (MS-6163
+rev:3) and perhaps also for MSI MS-6163FC (MS-6163 rev:1) but these
+boards have not been tested.
+
+Test logs for MS-6163 (rev:2):
+http://www.flashrom.org/pipermail/flashrom/2010-September/004704.html
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1159 | hailfinger | 2010-09-13 16:02:22 +0200 (Mon, 13 Sep 2010) | 10 lines
+
+Board enable for ASUS P5GDC Deluxe.
+
+Match on SMBus and Audio.
+lspci/superiotool/flashrom output:
+http://www.flashrom.org/pipermail/flashrom/2010-September/004689.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Tested-by: Alexander Mikhnovets <alexander.mikhnovets@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1158 | uwe | 2010-09-11 17:25:48 +0200 (Sat, 11 Sep 2010) | 15 lines
+
+Add a board enable for MSI MS-6561 (745 Ultra).
+
+SiS 745 chipset + Winbond W83697HF and Winbond W49F002U flash. Probe, read,
+erase and write all work.
+
+Matching on "NB/SB" (they are integrated). Also mark SiS 745 chipset
+as tested.
+
+lspci/superiotool:
+  http://www.flashrom.org/pipermail/flashrom/2010-September/004705.html
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1157 | mkarcher | 2010-09-10 16:54:18 +0200 (Fri, 10 Sep 2010) | 18 lines
+
+Board enable for P4P800
+
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-August/004436.html
+
+This goes the safe route of adding a match for the P4P800 that does not
+match the P4P800-E Deluxe which is already in.  It seems quite likely that
+the whole P4P800 family could use the same board enable with one generic
+board enable match, though.
+
+This match uses host bridge + audio, because all other IDs match the
+P4P800-E Deluxe board, as reported in
+ http://www.e-monkeys.de/Everest-Bericht.txt
+
+(no user feedback, commit as "untested")
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1156 | mkarcher | 2010-09-10 16:46:46 +0200 (Fri, 10 Sep 2010) | 10 lines
+
+Board enable for ASUS P5GD1 Pro
+
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-August/004539.html
+
+matching SMBus + Audio, because SMBus is the only core device with
+usable IDs.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1155 | uwe | 2010-09-07 20:14:53 +0200 (Tue, 07 Sep 2010) | 9 lines
+
+Add a board-enable for the MSI MS-6787 (P4MAM-V/P4MAM-L).
+
+Marked as untested for now, as there was no response from the user.
+
+Signed-off-by: Sergey A Lichack <shadowpilot34@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1154 | uwe | 2010-09-07 19:52:09 +0200 (Tue, 07 Sep 2010) | 14 lines
+
+Add board-enable for the GIGABYTE GA-K8N51GMF-9.
+
+Interestingly enough, this board's enable looked more like
+enable_flash_nvidia_nforce2 than enable_flash_ck804; it whacked
+0x92, not 0x88. But according to the lspci, 0x92 is already 0.
+
+Tested successfully on hardware:
+ http://www.flashrom.org/pipermail/flashrom/2010-August/004568.html
+ http://www.flashrom.org/pipermail/flashrom/2010-September/004575.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1153 | uwe | 2010-09-05 14:41:25 +0200 (Sun, 05 Sep 2010) | 61 lines
+
+Updates to the board and chips status tables (trivial).
+
+Mark the following boards as tested:
+
+ - Tyan S2933 (Thunder n3600S) (reported by Pendic Peter <nigma@bluewin.ch>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004375.html
+
+ - MSI MS-7642 (890GXM-G65) (reported by Alan McMahon <pam@aldersgate.co.uk>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004393.html
+
+ - Shuttle X50/X50(B) (reported by Ed Driesen <ed@omts.be>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004472.html
+   (the "B" variant is just black instead of white, no hardware differences
+    as far as I can see)
+
+ - ASUS M2NPV-VM (reported by Antti Palosaari <crope@iki.fi>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004476.html
+
+ - ZOTAC ZBOX HD-ID11 (reported by s. ewgen <sewgen@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004512.html
+
+ - ASRock A330GC (reported by Daniel Flinkmann <DFlinkmann@gmx.de>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004517.html
+
+ - Congatec conga-X852 (reported by Mario Rogen <Mario.Rogen@sie.at>)
+   http://www.coreboot.org/pipermail/coreboot/2008-November/041433.html
+
+ - IEI PICOe-9452 (reported by Mario Rogen <Mario.Rogen@sie.at>)
+   http://www.coreboot.org/pipermail/coreboot/2008-November/041433.html
+
+ - Lex CV700A (reported by Mario Rogen <Mario.Rogen@sie.at>)
+   http://www.coreboot.org/pipermail/coreboot/2008-November/041433.html
+
+ - Portwell PEB-4700VLA (reported by Mario Rogen <Mario.Rogen@sie.at>)
+   http://www.coreboot.org/pipermail/coreboot/2008-November/041433.html
+
+Mark the following chips as tested:
+
+ - SST SST39SF040 (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004414.html
+
+ - Eon EN25F80 (reported by Ed Driesen <ed@omts.be>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004472.html
+
+ - SyncMOS/MoselVitelic {F,S,V}29C51002T (reported by Mattias
+   Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004475.html
+
+ - PMC Pm29F002T (reported by Tadas S <mrtadis@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-September/004583.html
+
+Also:
+
+ - Fix a few whitespace issues and cosmetics while I'm at it.
+
+ - Add the board name (in addition to the Sxxxx number) to all Tyan boards.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1152 | hailfinger | 2010-09-05 01:37:40 +0200 (Sun, 05 Sep 2010) | 43 lines
+
+Success report for Atmel AT26DF081A from
+Oliver Schnatz <oliver.schnatz@mysys.de>
+http://www.flashrom.org/pipermail/flashrom/2009-October/000760.html
+
+Success report for Winbond W25Q32 from
+David Hendricks <dhendrix@google.com>
+http://www.flashrom.org/pipermail/flashrom/2010-April/002891.html
+
+Success report for SST SST39VF512 from
+Alec Wright <alecjw@member.fsf.org>
+http://www.flashrom.org/pipermail/flashrom/2010-August/004549.html
+http://www.flashrom.org/pipermail/flashrom/2010-August/004548.html
+
+Success report for Silicon Image SiI 3512 and AMD Am29LV040B from
+Michael Manulis <michael@manulis.com>
+http://www.flashrom.org/pipermail/flashrom/2010-July/003944.html
+
+Annotate listing with reporter/owner name for boards marked broken, flag
+boards for which no reports exist.
+- 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
+- Soyo SY-5VD
+- Sun Fire x4150
+- Sun Fire x4200
+- Sun Fire x4540
+- Sun Fire x4600
+
+Remove comments which are no longer appropriate:
+- ASRock K8S8X
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1151 | uwe | 2010-09-03 20:21:21 +0200 (Fri, 03 Sep 2010) | 18 lines
+
+Add Intel Gigabit NIC SPI flashing support.
+Tested on a 82541PI (0x8086, 0x107c) using 32-bit hardware.
+
+The last line in nicintel_request_spibus() could be changed so that FL_BUSY
+is used instead.
+
+Shortened sample log:
+[...]
+Found "Intel 82541PI Gigabit Ethernet Controller" (8086:107c, BDF 01:03.0).
+Found chip "ST M25P10.RES" (128 KB, SPI) at physical address 0xfffe0000.
+Multiple flash chips were detected: M25P05.RES M25P10.RES
+Please specify which chip to use with the -c <chipname> option.
+[...]
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1150 | hailfinger | 2010-09-03 05:35:48 +0200 (Fri, 03 Sep 2010) | 6 lines
+
+Add FEATURE_WRSR_WREN to feature_bits for all Macronix SPI flash chips
+to indicate that spi_write_status_register() needs WREN instead of EWSR.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1149 | hailfinger | 2010-09-03 05:32:22 +0200 (Fri, 03 Sep 2010) | 6 lines
+
+Add FEATURE_WRSR_WREN to feature_bits for some AMIC SPI flash chips
+to indicate that spi_write_status_register() needs WREN instead of EWSR.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1148 | hailfinger | 2010-09-03 05:18:26 +0200 (Fri, 03 Sep 2010) | 6 lines
+
+Add FEATURE_WRSR_WREN to feature_bits for many Eon SPI flash chips
+to indicate that spi_write_status_register() needs WREN instead of EWSR.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1147 | hailfinger | 2010-09-03 05:06:07 +0200 (Fri, 03 Sep 2010) | 6 lines
+
+Add FEATURE_WRSR_WREN to feature_bits for all Winbond SPI flash chips
+to indicate that spi_write_status_register() needs WREN instead of EWSR.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1146 | mhm | 2010-09-01 03:21:34 +0200 (Wed, 01 Sep 2010) | 10 lines
+
+Add board enable for Asus P2B-N.
+
+Many thanks to Michael Karcher for reverse engineering this.
+
+lspci/superio output:
+http://www.flashrom.org/pipermail/flashrom/2010-August/004475.html
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1145 | hailfinger | 2010-08-18 17:12:43 +0200 (Wed, 18 Aug 2010) | 18 lines
+
+Add paranoid checks for correct values in essential registers in the
+SB600/SB700/... SPI driver. If something else changes the values we
+wrote, we will see severe read/write corruption.
+sb600spi will now abort the access and return an error if it detects
+this sort of corruption.
+
+Note: This corruption can be caused by a few different events:
+- IPMI/BMC/IMC accesses flash
+- Other software accesses flash
+The nature of flash access (read/write/ID/...) is irrelevant. Each such
+access will cause corruption for all other accesses happening at the
+same time.
+
+Thanks to Matthias Kretz for testing this patch.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Matthias Kretz <kretz@kde.org>
+
+------------------------------------------------------------------------
+r1144 | mkarcher | 2010-08-17 00:12:39 +0200 (Tue, 17 Aug 2010) | 11 lines
+
+SST49FL040B: add unlocking
+
+The datasheet says there's a set of registers in the 4Mbit before the
+flash memory.  The block locking registers are aligned on 64K
+boundaries, plus 2.
+
+Write/erase sucessful on a system it failed before:
+  http://www.flashrom.org/pipermail/flashrom/2010-August/004432.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1143 | mkarcher | 2010-08-16 00:43:23 +0200 (Mon, 16 Aug 2010) | 7 lines
+
+Add board enable for Abit VA6
+
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-August/004440.html
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1142 | mkarcher | 2010-08-16 00:35:31 +0200 (Mon, 16 Aug 2010) | 21 lines
+
+Check availability of GPO lines on Intel PIIX4
+
+This patch changes the intel_piix4_gpo_set() function to always check
+the GENCFG and XBCS registers for the availability of the
+requested GPO line before raising/lowering it and fails otherwise. It
+makes no attempt to bypass the values in these configuration
+registers.
+
+The old flashrom code did consider it safe to reprogram (multiplexed)
+GPO:s 22-26 without checking the value of the controlling register
+(GENCFG). I do not really know why.
+
+I have tested this patch on an Asus P2B-N (needs GPO18 low) and MSI
+MS-6163 Pro (needs GPO14 high).
+
+The information for these registers are from the Intel "82371AB
+PCI-TO-ISA / IDE XCELERATOR (PIIX4)" datasheet available here:
+http://www.intel.com/design/intarch/datashts/29056201.pdf
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1141 | uwe | 2010-08-15 17:26:30 +0200 (Sun, 15 Aug 2010) | 46 lines
+
+Various board status updates and fixes (trivial).
+
+- There are number of boards that have board-enables in board-enable.c but
+  have no corresponding entry in print.c (with or without URL doesn't matter)
+  and thus appear neither in the "flashrom -L" list of boards nor in the
+  wiki output. Fix this by adding entries for them in print.c.
+
+   - abit AN-M2
+   - abit KN8 Ultra
+   - ASUS A8Jm (laptop)
+   - ASUS A8N (might need changing to "A8N-SLI Deluxe", see
+     http://www.coreboot.org/pipermail/flashrom/2009-November/000878.html)
+   - ASUS A8N-LA (Nagami-GL8E)
+   - ASUS P4B533-E
+   - ASUS P4S800-MX
+   - HP ProLiant DL165 G6
+   - IBASE MB899
+   - Intel SE440BX-2 (marked as non-working for now though, due to
+     http://www.coreboot.org/pipermail/flashrom/2010-July/003952.html)
+   - MSI MS-6577 (Xenon)
+   - MSI MS-7207 (K8NGM2-L)
+
+- Fix / amend a few board names:
+
+   - Add "ProLiant" name to the "DL145 G3" (and the new "DL165 G6"), we
+     use such "series" names for various other boards (e.g. "Vectra" etc)
+     and it also helps users googling for those names.
+
+   - HP "Vectra VL400 PC" should be "Vectra VL400" really, I'm pretty sure
+     the "PC" is not part of the board name but simply stands for
+     "personal computer". Same for "Vectra VL420 SFF PC".
+
+   - Change "ASUS A8JM" to "ASUS A8Jm" as per vendor website.
+
+   - Add comments for boards which may be listed with incorrect names,
+     I sent out clarification requests to the list, URLs listed as comment.
+
+   - Add "Xenon" HP name to the "MSI MS-6577" OEM board.
+
+   - Fix typo in "MS-7207 (K8N GM2-L)", should be "MS-7207 (K8NGM2-L)" as
+     per vendor website.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1140 | uwe | 2010-08-15 16:36:18 +0200 (Sun, 15 Aug 2010) | 13 lines
+
+Mark the board-enable for ASUS A8N-LA (HP OEM "Nagami-GL8E") as tested.
+
+Change the DMI string to only match this exact board (DMI "NAGAMI2L")
+as only this one is tested.
+
+Similar HP OEM boards might also work using this board-enable but that's
+not sure and not tested. Two of those boards have DMI strings "NAGAMI"
+and "NAGAMI2".
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1139 | mkarcher | 2010-08-15 12:21:29 +0200 (Sun, 15 Aug 2010) | 9 lines
+
+Board enable for MSI MS-7061 (KM4AM-V)
+
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-August/004414.html
+
+(URL added by Michael Karcher)
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1138 | mkarcher | 2010-08-13 14:49:01 +0200 (Fri, 13 Aug 2010) | 11 lines
+
+Board enable for GA-8PE667 Ultra 2
+
+I had to use the USB controller in the board enable because all other
+subsystem IDs are having vendor: Gigabyte but mostly copy the Intel
+product IDs.
+
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-August/004420.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Thomas Kalka <thomas.kalka@googlemail.com>
+------------------------------------------------------------------------
+r1137 | mkarcher | 2010-08-11 23:06:10 +0200 (Wed, 11 Aug 2010) | 8 lines
+
+Add support for Intel 5 Series / 3400 Series chipsets
+
+(At least) for the QM57 which i have tested an additional patch was
+needed as some reserved bits in the "Software Sequencing Flash Control
+Register" (SSFC) needs to be programmed to 1 in the QM57.
+
+Signed-off-by: Helge Wagner <helge.wagner@ge.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1136 | mkarcher | 2010-08-08 23:56:52 +0200 (Sun, 08 Aug 2010) | 9 lines
+
+Add dmidecode quirk workaround
+
+dmidecode emits a warning message about unsupported SMBIOS versions
+to stdout before the information asked for when using "-s". I consider
+this behaviour broken, but we still need to workaround it as e.g. Fedora
+currently distributes an dmidecode with this behaviour.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r1135 | uwe | 2010-08-08 19:04:21 +0200 (Sun, 08 Aug 2010) | 6 lines
+
+Fix typo (s/Bit/Bits/) to clarify code comment.
+Signed-off-by: David Borg <borg.db@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1134 | uwe | 2010-08-08 19:01:18 +0200 (Sun, 08 Aug 2010) | 20 lines
+
+Various cosmetic and coding-style fixes (trivial).
+
+ - Fix incorrect whitespace, indentation, and coding style in some places.
+
+ - Drop '/**' Doxygen comments, we don't use Doxygen. Even if we would use
+   it, the comments are useless as we don't have any Doxygen markup in there.
+
+ - Use consistent vendor name spelling as per current website (NVIDIA,
+   abit, GIGABYTE).
+
+ - Use consistent / common format for "Suited for:" lines in board_enable.c.
+
+ - Add some missing 'void's in functions taking no arguments.
+
+ - Add missing fullstops in sentences, remove them from non-sentences (lists).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1133 | uwe | 2010-08-08 18:05:23 +0200 (Sun, 08 Aug 2010) | 10 lines
+
+Add a board-enable for the ASRock 775i65G.
+
+This was successfully tested by 'kai2343' on IRC.
+
+Thanks to Michael Karcher for finding the board enable.
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1132 | uwe | 2010-08-08 17:52:07 +0200 (Sun, 08 Aug 2010) | 41 lines
+
+Mark the following boards/chips as tested (trivial).
+
+Boards:
+
+ - ASUS M4A785TD-M EVO (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004283.html
+
+ - ASUS M2N32-SLI Deluxe (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004287.html
+
+ - ASUS P2E-M (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004261.html
+
+ - ASUS M2N-SLI Deluxe (reported by
+   Kasper M. Nielsen <kasper.nielsen85@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003015.html
+   
+ - iBASE MB899 (reported by Bernhard M. Wiedemann <bernhard@lsmod.de>)
+   http://www.flashrom.org/pipermail/flashrom/2010-April/002953.html
+   
+   Board-enable is now marked as tested.
+
+ - ASRock 939A785GMH/128M (reported by
+   Lennart Sauerbeck <lists@lennart.sauerbeck.org>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004340.html
+
+Chips:
+ - ST M50FLW080A (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004287.html
+ - Winbond W29EE011 (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004261.html
+ - SST SST49LF040 (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-August/004296.html
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1131 | mkarcher | 2010-08-07 23:49:11 +0200 (Sat, 07 Aug 2010) | 9 lines
+
+Board enable for MSI MS-6577
+
+Thanks to "Putlinuxonit" <putlinuxonit@gmail.com> for reporting
+and testing.
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-August/004309.html
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1130 | mkarcher | 2010-08-02 10:29:34 +0200 (Mon, 02 Aug 2010) | 7 lines
+
+Board enable for Asus P4S800-MX
+
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-July/004172.html
+
+Signed-off-by: David Borg <borg.db@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1129 | uwe | 2010-08-01 02:13:49 +0200 (Sun, 01 Aug 2010) | 55 lines
+
+Further chip and board status updates (trivial).
+
+Mark the following boards as supported:
+
+ - Foxconn A6VMX (reported by Alec Wright <alecjw@member.fsf.org>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004186.html
+
+ - GIGABYTE GA-8IRML (reported by Putlinuxonit <putlinuxonit@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004175.html
+
+   Marking the board-enable as tested now.
+
+ - MSI MS-7253 (K9VGM-V) (reported by Alex <cerebro.alexiel@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003411.html
+
+ - Soyo SY-6BA+ III (reported by Andrew Morgan <ziltro@ziltro.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003409.html
+
+ - GIGABYTE GA-770TA-UD3 (reported by Hering <boerni@pakke.de>)
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003267.html
+
+ - Shuttle AV11V30 (reported by
+   "N?\195?\169stor a.k.a. DarkMan" <master_darkman@hotmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003260.html
+
+ - Tyan S3992 (reported by Alessandro Gervaso <gervaso@appliedgenomics.org>)
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003129.html
+
+ - GIGABYTE GA-MA785GMT-UD2H (reported by
+   Dominick Layfield <dom.layfield@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003061.html
+
+Mark the following chips as tested:
+
+ - ST M25P10-A (reported by Joshua Blanton <jblanton@rldrake.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003451.html
+
+ - ST M50FLW080A (reported by Vincent Pelletier <plr.vincent@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003410.html
+
+   Marked PROBE and READ as tested.
+
+ - SST SST39SF020A (reported by Andrew Morgan <ziltro@ziltro.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003409.html
+
+ - AMD Am29F010A/B (reported by Andrew Morgan <ziltro@ziltro.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003335.html
+
+ - SST SST39VF010 (reported by Tim Small <tim@buttersideup.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003310.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1128 | hailfinger | 2010-08-01 01:16:09 +0200 (Sun, 01 Aug 2010) | 7 lines
+
+Add support for SIS661 (SIS963).
+
+Tested on Asus P4S800-MX.
+
+Signed-off-by: David Borg <borg.db@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1127 | uwe | 2010-07-30 19:08:29 +0200 (Fri, 30 Jul 2010) | 10 lines
+
+Mark the following boards as supported:
+
+ - Elitegroup RS485M-M
+
+ - Biostar TA780G M2+
+
+Signed-off-by: Daniel Lenski <dlenski@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1126 | uwe | 2010-07-30 00:39:47 +0200 (Fri, 30 Jul 2010) | 65 lines
+
+Mark the following chips/boards/PCI-cards as OK (trivial).
+
+Chips:
+
+ - Winbond W25x80 (reported by Michael Cole <michaelcole@michaelcole.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004176.html
+
+ - Winbond W25Q80 (reported by Jonathan A. Kollasch <jakllsch@kollasch.net>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/003847.html
+
+ - SST SST25VF080B (reported by Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/003807.html
+
+   Also reported by Daniel Flinkmann <dflinkmann@gmx.de>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003659.html
+
+ - Winbond W25x16 (reported by Michael Dunphy <mdunphy@uwaterloo.ca>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003631.html
+
+ - Atmel AT25DF321 (reported by
+   Ramakrishna Kvv <Ramakrishna.Koduri@emerson.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003529.html
+
+ - Winbond W25x40 (reported by Prakash J Kokkatt <pjkonweb@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003502.html
+
+ - Winbond W49V002A (reported by David <dung@aon.at>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003375.html
+
+ - Macronix MX25L8005 (reported by Peter Lemenkov <lemenkov@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003373.html
+
+   Also reported by Alec Wright <alecjw@member.fsf.org>.
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004186.html
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004159.html
+
+   Also reported by J?\195?\182rg Fischer <turboj@gmx.de>.
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004080.html
+
+   Also reported by Kevin Malec <kevin.010@gmail.com>.
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003698.html
+
+   Heck, also reported by myself (tested on hardware, never sent mail).
+
+ - SST SST49LF002A/B (reported by Udu Ogah <putlinuxonit@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004184.html
+
+ - SST SST49LF160C (reported by Ed Swierk <eswierk@aristanetworks.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003634.html
+
+Mark the following boards as supported:
+
+ - ASUS M3A76-CM (reported by Kevin Malec <kevin.010@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003698.html
+
+Mark the following PCI cards as supported:
+
+ - "Silicon Image SiI 3124 PCI-X SATA Ctrl" (1095:3124)
+   Reported by Max Kalashnikov <mmt@maxkalashnikov.com>
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004007.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1125 | uwe | 2010-07-29 23:15:45 +0200 (Thu, 29 Jul 2010) | 6 lines
+
+Mark GIGABYTE GA-MA74GM-S2H (rev. 3.0) as supported.
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1124 | hailfinger | 2010-07-29 22:01:13 +0200 (Thu, 29 Jul 2010) | 18 lines
+
+Add definitions for the following chips:
+
+Mosel Vitelic Corporation:
+V29C51000B, V29C51000T, V29C51400B, V29C51400T, V29LC51000, V29LC51001,
+V29LC51002
+
+SyncMOS / Mosel Vitelic Corporation:
+{F,S,V}29C51001B, {F,S,V}29C51001T, {F,S,V}29C51002B, {F,S,V}29C51002T,
+{F,S,V}29C51004B, {F,S,V}29C51004T, {V,S}29C31004B, {V,S}29C31004T
+
+Modify earlier definitions of
+S29C31004T/S29C51001T/S29C51002T/S29C51004T to change name and correct
+page size.
+
+Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1123 | uwe | 2010-07-29 21:57:55 +0200 (Thu, 29 Jul 2010) | 9 lines
+
+ft2232_spi: Cosmetic fixes (trivial).
+
+Various whitespace- and cosmetic fixes. Also, Use %04x:%04x for printing
+the USB IDs (which are 4 hex digits long), not %02x:%02x.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1122 | uwe | 2010-07-29 21:26:15 +0200 (Thu, 29 Jul 2010) | 51 lines
+
+Mark the following boards as tested OK (trivial).
+
+ - ASUS M4A79T Deluxe (reported by Michael Cole <michaelcole@michaelcole.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004176.html
+
+ - Tyan S2915 (Thunder n6650W) (reported by
+   Axel Bergerhoff <axelbergerhoff@compuserve.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/004140.html
+
+ - ASRock ALiveNF6G-DVI (reported by Sven Lankes <sven@lank.es>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/003951.html
+
+ - ASUS M4A87TD/USB3 (reported by Jonathan A. Kollasch <jakllsch@kollasch.net>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/003847.html
+
+ - Fujitsu-Siemens ESPRIMO P5915 (reported by
+   Mattias Mattsson <vitplister@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-July/003807.html
+
+ - ASUS P6T SE (reported by Michael Dunphy <mdunphy@uwaterloo.ca>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003631.html
+
+   Also reported by Sinisa Dukanovic <sinisa@dukanovic.com>.
+   http://www.flashrom.org/pipermail/flashrom/2010-January/001799.html
+
+ - Emerson ATCA-7360 (reported by
+   Ramakrishna Kvv <Ramakrishna.Koduri@emerson.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003529.html
+
+ - ASUS P5GC-MX/1333 (reported by Prakash J Kokkatt <pjkonweb@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003502.html
+
+ - Elitegroup P6IWP-Fe (reported by Anders Jenbo <anders@jenbo.dk>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003419.html
+
+ - Biostar M7NCD Pro (reported by David <dung@aon.at>)
+   http://www.flashrom.org/pipermail/flashrom/2010-June/003375.html
+
+Mark the "HP Compaq nx9005" laptop as non-supported for now.
+Reported by Anders <mail@jagtogfiskerimagasinet.dk>.
+http://www.flashrom.org/pipermail/flashrom/2010-May/003321.html
+
+Fix "Samsung Polaris 32" URL entry from "" to NULL, otherwise the wiki
+output is broken.
+
+Also do some minor whitespace fixing in print.c.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1121 | hailfinger | 2010-07-29 18:32:24 +0200 (Thu, 29 Jul 2010) | 9 lines
+
+The AAI code rewrite in r1052 introduced a bug: The writelen of AAI
+continuation is 3 bytes, but the code incorrectly had 6 bytes there.
+This causes all AAI writes (except the first two bytes of a chip) to
+fail.
+Thanks to den_m for reporting the bug and for testing the fix.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1120 | hailfinger | 2010-07-29 18:24:09 +0200 (Thu, 29 Jul 2010) | 13 lines
+
+If we violate the raw SPI communication protocol requirements of the Bus
+Pirate (namely, waiting for the completion of one command before sending
+the next one), we can reduce the number of round trips by a factor of 3.
+The FT2232 chip present in the Bus Pirate has a big enough buffer (at
+least 128 bytes IIRC) to avoid overflows in the tiny buffer of the Bus
+Pirate PIC.
+
+Thanks to Daniel Flinkmann for sponsoring development of this patch.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Daniel Flinkmann <DFlinkmann@gmx.de>
+Acked-by: Daniel Flinkmann <dflinkmann@gmx.de>
+
+------------------------------------------------------------------------
+r1119 | hailfinger | 2010-07-29 17:54:53 +0200 (Thu, 29 Jul 2010) | 18 lines
+
+Add support for the Amontec JTAGkey2, see
+http://www.amontec.com/jtagkey2.shtml
+http://www.amontec.com/jtagkey.shtml
+
+This FTDI 2232H variant has an additional output enable, which will be
+set to its "on" (L) when CS is pulled low.
+But it lacks a power supply and you need an external 3.3V source.
+
+The attached patch adds "jtagkey" as "type" parameter for ft2232_spi.
+It should work with all JTAGkeys (JTAGkey, JTAGkey-tiny and JTAGkey2)
+but I only have a JTAGkey2 here for testing.
+
+Add all FT2232H/FT4232H based programmers to the list printed with
+flashrom -L
+
+Signed-off-by: J?\195?\182rg Fischer <turboj@gmx.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1118 | hailfinger | 2010-07-29 17:00:40 +0200 (Thu, 29 Jul 2010) | 7 lines
+
+Add support for
+AMIC A25L512, A25L010, A25L020, A25L040, A25L080, A25L016, A25L032
+AMIC A25LQ032 (quad-rate read)
+
+Signed-off-by: Dan Lenski <dlenski@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1117 | hailfinger | 2010-07-29 16:41:46 +0200 (Thu, 29 Jul 2010) | 5 lines
+
+Compile gfxnvidia by default, but disallow write/erase.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1116 | hailfinger | 2010-07-29 15:17:37 +0200 (Thu, 29 Jul 2010) | 7 lines
+
+Allow compilation on all architectures even if direct hardware access
+primitives are missing, if all you need is userspace access to the
+serial port (serprog, buspirate) or no access at all (dummy).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1115 | hailfinger | 2010-07-29 15:09:18 +0200 (Thu, 29 Jul 2010) | 13 lines
+
+Add detailed status register printing and unlocking for all ATMEL AT25*
+chips.
+
+Add support for Atmel AT25DF081A and AT25DQ161.
+
+Some chips require EWSR before WRSR, others require WREN before WRSR,
+and some support both variants. Add feature_bits to select the correct
+SPI command, and default to EWSR.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Steven Rosario
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1114 | hailfinger | 2010-07-29 00:20:20 +0200 (Thu, 29 Jul 2010) | 7 lines
+
+Cosmetics.
+Fix alphabetic sort order for manufacturers in flashchips.c.
+Rename a few EON chips to Eon.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1113 | hailfinger | 2010-07-28 17:08:35 +0200 (Wed, 28 Jul 2010) | 28 lines
+
+Add Nvidia nForce MCP61/MCP65/MCP67/MCP78S/MCP73/MCP79 SPI flashing
+support.
+
+Huge thanks go to Michael Karcher for reverse engineering the interface
+and to Johannes Sj?\195?\182lund for testing the first iterations of my patch on
+his hardware until it worked.
+
+Thanks to the following testers of the patch:
+* MCP61, 10de:03e0, LPC OK, ECS Geforce6100SM-M, Andrew Cleveland
+* MCP61, 10de:03e0, LPC OK, Biostar NF520-A2 NF61D-A2, Vitaliy Buchynskyy
+* MCP65, 10de:0441, SPI OK, MSI MS-7369 K9N Neo-F v2, Kjell Braden
+* MCP65, 10de:0441, SPI OK, MSI MS-7369, Wolfgang Schnitker
+* MCP65, 10de:0441, SPI OK, MSI MS-7369, Johannes Sj?\195?\182lund
+* MCP65, 10de:0441, SPI OK, MSI MS-7369, Melchior Franz
+* MCP78S, 10de:075c, SPI OK, Asus M3N78 PRO, Brad Rogers
+* MCP78S, 10de:075c, SPI OK, Asus M3N78-VM, Marcel Partap
+* MCP78S, 10de:075c, SPI OK, Asus M4N78 PRO, Kimmo Vuorinen
+* MCP78S, 10de:075c, SPI OK, Asus M4N78 PRO, Vikram Ambrose
+* MCP79, 10de:0aad, SPI OK, Acer Aspire R3600, Andrew Morgan
+* MCP79, 10de:0aae, LPC ??, Lenovo Ideapad S12 laptop, Christian Schmitt
+* MCP79, 10de:0aae, SPI OK, Apple iMac9,1 Mac-F2218EA9, David "dledson"
+
+flashrom will refuse to write/erase for safety reasons if MCP6x/MCP7x
+SPI is detected.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1112 | hailfinger | 2010-07-28 00:41:39 +0200 (Wed, 28 Jul 2010) | 18 lines
+
+Split off programmer.h from flash.h.
+Programmer specific functions are of absolutely no interest to any file
+except those dealing with programmer specific actions (special SPI
+commands and the generic core).
+
+The new header structure is as follows (and yes, improvements are
+possible):
+flashchips.h  flash chip IDs
+chipdrivers.h  chip-specific read/write/... functions
+flash.h  common header for all stuff that doesn't fit elsewhere
+hwaccess.h hardware access functions
+programmer.h  programmer specific functions
+coreboot_tables.h  header from coreboot, internal programmer only
+spi.h SPI command definitions
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1111 | hailfinger | 2010-07-28 00:03:46 +0200 (Wed, 28 Jul 2010) | 27 lines
+
+Convert all PCI-based external programmers to use special little-endian
+accessors for all MMIO regions of PCI devices.
+This patch does _not_ touch the internal programmer (which is PCI-based
+as well).
+
+Huge thanks go to Misha Manulis who worked with me to create a first
+version of this patch for the satasii programmer based on modification
+of generic code.
+
+Huge thanks also go to Segher Boessenkool for suggesting the pci_mmio_
+prefix for the abstraction layer.
+
+NOTE to package maintainers:
+With this patch, compilation and usage of flashrom should be safe on
+x86, x86_64, MIPS (little and big endian) and PowerPC (big endian).
+
+The internal programmer is disabled on non-x86/x86_64 (but it compiles).
+The atahpt, nic3com, nicnatsemi, nicrealtek and rayer_spi can not be
+compiled on non-x86/x86_64 because port space I/O is not (yet)
+supported. Please compile with default settings on x86/x86_64 and with
+the following settings on all other architectures:
+make CONFIG_NIC3COM=no CONFIG_NICREALTEK=no CONFIG_NICNATSEMI=no
+     CONFIG_RAYER_SPI=no
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Misha Manulis <misha@manulis.com>
+
+------------------------------------------------------------------------
+r1110 | uwe | 2010-07-28 00:00:42 +0200 (Wed, 28 Jul 2010) | 22 lines
+
+Add a udev rules file for flashrom.
+
+This allows USB-based external programmers to be used by non-root users
+(which are in the 'plugdev' group). The file is to be installed by the
+distros into the proper place (not sure if this is distro-specific). On
+Debian the file will end up in /etc/udev/rules.d/z60_flashrom.rules.
+
+On some systems the 'plugdev' group might have to adapted to whatever
+the respective distro uses.
+
+The following devices are listed so far:
+
+ - Amontec JTAGkey(2)
+ - Buspirate
+ - Dediprog SF100
+ - DLP Design DLP-USB1232H
+ - FTDI FT4232H Mini-Module
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1109 | mkarcher | 2010-07-25 00:50:54 +0200 (Sun, 25 Jul 2010) | 13 lines
+
+Board enable for abit NF-M2 nView
+
+To be safe, the onboard video of the nView edition of this board has
+been included in the match. If other NF-M2 editions have the same board
+enable, the match should be broadened
+
+lspci/superiotool
+  http://www.coreboot.org/pipermail/flashrom/2010-April/002909.html
+
+No success report, thus committed as untested.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1108 | mkarcher | 2010-07-25 00:43:12 +0200 (Sun, 25 Jul 2010) | 14 lines
+
+Detect IP35 by the SMBus bridge instead of the SATA controller
+
+The SATA controller matched in the board enable is not always present
+with that ID (that's the 2-port ICH9 SATA IDE controller), but (depending
+on board revision/edition or BIOS settings an ICH9 SATA RAID controller
+appears instead. This patches matches on the SMBus function in the
+south bridge instead of the SATA controller.
+
+Non-working board reported by: Gunter Keilholz <gunter.keilholz@googlemail.com>
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-June/003591.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1107 | mkarcher | 2010-07-25 00:36:01 +0200 (Sun, 25 Jul 2010) | 8 lines
+
+Board enable for Samsung Polaris 32
+
+lspci/superiotool:
+http://www.coreboot.org/pipermail/flashrom/2010-July/003889.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Tested-by: Alex Loktionoff <oxy-loktionoff@mail.ru>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1106 | mkarcher | 2010-07-25 00:27:29 +0200 (Sun, 25 Jul 2010) | 9 lines
+
+Board enable for GA-8IRML
+
+Non-working board reported by idlogin / Putlinuxonit <putlinuxonit@gmail.com>
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-May/003330.html
+No success report, so committed as untested.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1105 | mkarcher | 2010-07-25 00:18:14 +0200 (Sun, 25 Jul 2010) | 10 lines
+
+board enable for Abit IC7
+
+Non-working board reported by: Anders Jenbo <anders@jenbo.dk>
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-June/003346.html
+
+no success report, so committed as untested.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1104 | mkarcher | 2010-07-25 00:07:52 +0200 (Sun, 25 Jul 2010) | 6 lines
+
+Fix compilation for CONFIG_INTERNAL=no
+
+broken by r1098
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1103 | hailfinger | 2010-07-24 20:47:45 +0200 (Sat, 24 Jul 2010) | 5 lines
+
+Fix compilation which was broken by r1101.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1102 | mkarcher | 2010-07-24 13:14:37 +0200 (Sat, 24 Jul 2010) | 7 lines
+
+Board enable for HP Puffer2-UL8E
+
+lspci/superiotool:
+  http://www.coreboot.org/pipermail/flashrom/2010-July/003869.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Mattias Mattsson <vitplister@gmail.com>
+------------------------------------------------------------------------
+r1101 | mkarcher | 2010-07-24 13:03:48 +0200 (Sat, 24 Jul 2010) | 6 lines
+
+Board enable for ASUS P4SD-LA (HP OEM)
+
+No response from reporter - committed as "untested".
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1100 | mkarcher | 2010-07-24 12:41:42 +0200 (Sat, 24 Jul 2010) | 5 lines
+
+Board enable for ASUS P5PE-VM
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Tested-by: Franti?\197?\161ek Ku?\196?\141era <linux@frantovo.cz>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1099 | mkarcher | 2010-07-22 20:04:19 +0200 (Thu, 22 Jul 2010) | 4 lines
+
+Move SB600 SPI initialization to sb600spi.c
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1098 | mkarcher | 2010-07-22 20:04:15 +0200 (Thu, 22 Jul 2010) | 8 lines
+
+Move Intel SPI initialisation to ichspi.c
+
+Smarter version could decide whether SPI is vital or not depending on
+straps. Straps are currently implemented for ICH7. EP80579 is in the comment,
+PCH of 5 Series/3400 Series has "LPC, reserved, PCI, SPI".
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1097 | hailfinger | 2010-07-22 17:20:43 +0200 (Thu, 22 Jul 2010) | 5 lines
+
+Add support for the Intel 28F002BC-T.
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1096 | hailfinger | 2010-07-22 13:44:38 +0200 (Thu, 22 Jul 2010) | 23 lines
+
+Add support for the following AMIC SPI chips:
+http://www.amictechnology.com/pdf/A25L20P.pdf covers:
+AMIC A25L05PT
+AMIC A25L05PU
+AMIC A25L10PT
+AMIC A25L10PU
+AMIC A25L20PT
+AMIC A25L20PU
+http://www.amictechnology.com/pdf/A25L16P.pdf covers:
+AMIC A25L16PT
+AMIC A25L16PU
+
+Clarify the situation surrounding the A25L40PT and A25L40PU chips which
+share the same RDID values, despite the fact that their erase block
+layouts are different.  Rudolf Marek tested and confirmed the distinct
+erase block layouts of these chips.
+
+Add a pretty-printer for the AMIC SPI chip status register
+Add a generic AMIC chip type.
+
+Signed-off-by: Daniel Lenski <dlenski@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1095 | hailfinger | 2010-07-21 17:12:07 +0200 (Wed, 21 Jul 2010) | 7 lines
+
+Add nicnatsemi to print.c and print_wiki.c.
+Change the nicnatsemi address mask to use MA0-MA16 and set the maximum
+decode size to 128KB.
+
+Signed-off-by: Andrew Morgan <ziltro@ziltro.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1094 | hailfinger | 2010-07-21 17:02:22 +0200 (Wed, 21 Jul 2010) | 5 lines
+
+Add support for the SST25VF064C SPI flash chip.
+
+Signed-off-by: Ed Swierk <eswierk@aristanetworks.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1093 | hailfinger | 2010-07-21 12:26:01 +0200 (Wed, 21 Jul 2010) | 30 lines
+
+Add support for RayeR SPIPGM hardware as described in
+http://rayer.ic.cz/elektro/spipgm.htm
+
+To use the RayeR driver, run
+flashrom -p rayer_spi -V
+
+Known bugs/limitations:
+- Won't compile/work on non-x86 architectures.
+- Will always use direct port I/O access.
+
+Log follows:
+
+flashrom v0.9.2-r1039 on MS-DOS 7 (i686), built with libpci 3.1.5, GCC 
+4.3.2, little endian
+Calibrating delay loop... OK.
+Initializing rayer_bitbang_spi programmer
+Using port 0x378 as I/O base for parallel port access.
+...
+Probing for Macronix MX25L1605, 2048 KB: probe_spi_rdid_generic: id1 
+0xc2, id2 0x2015
+...
+Found chip "Macronix MX25L1605" (2048 KB, SPI) at physical address 
+0xffe00000.
+...
+No operations were specified.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Martin Rehak <rayer@seznam.cz>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1092 | hailfinger | 2010-07-18 16:42:28 +0200 (Sun, 18 Jul 2010) | 6 lines
+
+Check during SPI bitbang init that SPI bitbang master configuration is
+correct.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1091 | mkarcher | 2010-07-18 01:27:47 +0200 (Sun, 18 Jul 2010) | 4 lines
+
+Use struct pointer instead of enum to set bitbang adapter
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1090 | hailfinger | 2010-07-18 01:21:12 +0200 (Sun, 18 Jul 2010) | 9 lines
+
+Print supported flash chips as narrow as possible.
+Fix a bug where 4 GB of spaces would be printed per line if a vendor
+name was longer than 10 chars.
+
+This patch is needed to commit MoselVitelic chip support.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1089 | hailfinger | 2010-07-18 00:42:33 +0200 (Sun, 18 Jul 2010) | 10 lines
+
+Use the BAR value returned by pcidev_init which automatically applies
+the correct BAR mask for the drkaiser driver.
+Truncate flash chip addresses to fit into the 128 kB memory window for
+drkaiser and pick the same window size for gfxnvidia.
+
+Uwe tested all operations successfully on a Dr. Kaiser card.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1088 | hailfinger | 2010-07-18 00:28:05 +0200 (Sun, 18 Jul 2010) | 6 lines
+
+Add support for pciutils/libpci older than 2.2. Needed on the original
+Xbox running Xebian and a few other ancient systems.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Alec Wright <alecjw@member.fsf.org>
+
+------------------------------------------------------------------------
+r1087 | hailfinger | 2010-07-17 16:49:30 +0200 (Sat, 17 Jul 2010) | 10 lines
+
+Newer llvm/clang versions (since r102686) have a __clang_version__ macro
+which can be used to print the exact clang version.
+
+Fix a case where chip_to_probe was referenced twice via extern, once at
+the function level and once in a global include file. Found by latest
+clang.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1086 | hailfinger | 2010-07-17 15:45:42 +0200 (Sat, 17 Jul 2010) | 5 lines
+
+Add Winbond W49F020 support. This chip is used on some Xbox versions.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Alec Wright <alecjw@member.fsf.org>
+
+------------------------------------------------------------------------
+r1085 | hailfinger | 2010-07-17 14:54:09 +0200 (Sat, 17 Jul 2010) | 12 lines
+
+Change the SPI bitbanging core to fix a subtle bug (which had no effect
+so far) and to make integration of the RayeR SPIPGM and Nvidia
+MCP6x/MCP7x SPI patches easier.
+Kill a few global variables and require explicit initialization of
+bitbanging delay.
+
+A big thank you to Johannes Sj?\195?\182lund for testing an earlier version of
+the code as part of the Nvidia MCP6x/MCP7x SPI bitbanging patch.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1084 | mkarcher | 2010-07-17 12:42:34 +0200 (Sat, 17 Jul 2010) | 10 lines
+
+remove temporary buffers from bitbanging
+
+This removes the need of allocating an extra buffer, but also removes
+the possibility of having the data read back during the initial write
+phase for debugging purposes.
+
+Compile tested, no functional testing.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1083 | hailfinger | 2010-07-17 00:07:20 +0200 (Sat, 17 Jul 2010) | 8 lines
+
+Mark Fujitsu MBM29F400BC write as broken (implicit eraseblock layout in
+write).
+Use full-chip write function on Fujitsu MBM29F400TC and ST M29F400BT.
+Add support for ST M29F400BB.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1082 | hailfinger | 2010-07-14 22:21:22 +0200 (Wed, 14 Jul 2010) | 6 lines
+
+We have a generic unlocking infrastructure. Use it for SPI chips.
+Actually check if the unlock worked instead of just assuming it worked.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1081 | hailfinger | 2010-07-14 21:57:52 +0200 (Wed, 14 Jul 2010) | 6 lines
+
+Use the max_rom_decode infrastructure for wbsio_spi instead of
+open-coding a variant which only aborts after it is too late.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1080 | hailfinger | 2010-07-14 18:19:05 +0200 (Wed, 14 Jul 2010) | 10 lines
+
+Convert SPI chips to partial write, but wrap the write functions in a
+compat layer to allow converting the rest of flashrom later.
+I actually have patches for most of the remaining conversion, but I
+wanted to get this out and reviewed first.
+
+Tested on Intel NM10 by David Hendricks.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1079 | hailfinger | 2010-07-14 01:56:13 +0200 (Wed, 14 Jul 2010) | 16 lines
+
+Print an error message on read errors and abort instead of proceeding
+anyway.
+Improve error checking in file write, chip read and chip verify.
+Refactor the read routines a bit to split reading from file writing.
+
+Log for a failed read:
+[...]
+Found chip "Winbond W25x16" (2048 KB, SPI) at physical address
+0xffe00000.
+Reading flash... Invalid OPCODE 0x03
+Read operation failed!
+FAILED.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-By: Stephen Kou <stephen@hyarros.com>
+
+------------------------------------------------------------------------
+r1078 | hailfinger | 2010-07-13 02:42:00 +0200 (Tue, 13 Jul 2010) | 5 lines
+
+Wrap a line which was 156 columns wide.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1077 | hailfinger | 2010-07-13 02:37:19 +0200 (Tue, 13 Jul 2010) | 7 lines
+
+Split erase region walking out of erase_flash.
+That allows us to use erase region walking for a combined erase/write
+action, and is a prerequisite for partial flashing,
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1076 | hailfinger | 2010-07-13 02:04:52 +0200 (Tue, 13 Jul 2010) | 11 lines
+
+Fix out-of-bounds ICH FREG permission printing. A bit was masked, but
+not shifted, and that led to worst-case accesses of index 24 in an array
+with 4 members.
+
+I've improved readability in the variable declaration block as well.
+
+Thanks to Stephen Kou for reporting the bug.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stephen Kou <stephen@hyarros.com>
+
+------------------------------------------------------------------------
+r1075 | mkarcher | 2010-07-11 23:33:31 +0200 (Sun, 11 Jul 2010) | 12 lines
+
+Add support for the AMIC A25L80P.  This is a 1 MB SPI
+chip that seems to be straightforwardly related to the AMIC A25L40PU, which
+has half the capacity but is otherwise identical.
+
+Datasheet is at http://www.amictechnology.com/pdf/A25L80P.pdf
+
+flashrom -VE, -Vr, and -Vw has been tested using the AMD SB7x0 interface.
+Everything works fine...  at least, I used it to upgrade my BIOS and I've
+been able to reboot.
+
+Signed-off-by: Daniel Lenski <dlenski@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1074 | mkarcher | 2010-07-10 21:34:15 +0200 (Sat, 10 Jul 2010) | 8 lines
+
+Fix read function for EMST F25L008A
+
+SPI chips never should use read_memmapped. The SPI master code might
+decide that read_memmapped is fine for this chip, though, in a lower
+layer.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1073 | hailfinger | 2010-07-10 18:56:32 +0200 (Sat, 10 Jul 2010) | 14 lines
+
+Autodetect the ITE IT8705 Super I/O and enable flash writes if it
+performs LPC->Parallel translation.
+Remove board enables which triggered the IT8705 write enable manually.
+Change the IT87 SPI special case to cover IT87 LPC->SPI and
+LPC->Parallel translation.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Tested on Syntax SV266A.
+Acked-by: Paul Menzel <paulepanter@users.sourceforge.net>
+
+Tested on Shuttle AK38N, all operations work fine.
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1072 | hailfinger | 2010-07-08 12:13:37 +0200 (Thu, 08 Jul 2010) | 8 lines
+
+Make programmer_param static by converting all users to
+extract_programmer_param.
+Programmer parameters can no longer be separated with a
+colon, they have to be separated with a comma.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1071 | mkarcher | 2010-07-08 11:32:18 +0200 (Thu, 08 Jul 2010) | 9 lines
+
+Fix ASUS A8N-VM CSM board enable entry
+
+r1063 had several issues: The PCI IDs for this board are copy/pasted from
+the A8N and plain wrong for this board and the board enable is marked as
+tested although it isn't. Finally the board description was slightly
+wrong and the URL missing.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1070 | hailfinger | 2010-07-06 11:55:48 +0200 (Tue, 06 Jul 2010) | 16 lines
+
+Various places in the flashrom source feature custom parameter
+extraction from programmer_param. This led to wildly differing syntax
+for programmer parameters, and it also voids pretty much every
+assumption you could make about programmer_param. The latter is a
+problem for libflashrom.
+
+Use extract_param everywhere, clean up related code and make it more
+foolproof.
+Add two instances of exit(1) where we have no option to return an error.
+Remove six instances of exit(1) where returning an error was possible.
+
+WARNING: This changes programmer parameter syntax for a few programmers!
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1069 | hailfinger | 2010-07-03 14:14:25 +0200 (Sat, 03 Jul 2010) | 9 lines
+
+If a programmer has untested or non-working write/erase code, but
+probing/reading works, it makes sense to protect the user against
+write/erase accidents.
+This feature will be used by the Nvidia MCP SPI code, and it also might
+make sense for the gfxnvidia driver which has non-working write/erase.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1068 | hailfinger | 2010-07-03 13:02:10 +0200 (Sat, 03 Jul 2010) | 20 lines
+
+Kill global variables, constants and functions if local scope suffices.
+Constify variables where possible.
+Initialize programmer-related variables explicitly in programmer_init to
+allow running programmer_init from a clean state after
+programmer_shutdown.
+Prohibit registering programmer shutdown functions before init or after
+shutdown.
+Kill some dead code.
+Rename global variables with namespace-polluting names.
+Use a previously unused locking helper function in sst49lfxxxc.c.
+
+This is needed for libflashrom.
+
+Effects on the binary size of flashrom are minimal (300 bytes
+shrinkage), but the data section shrinks by 4384 bytes, and that's a
+good thing if flashrom is operating in constrained envionments.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1067 | hailfinger | 2010-07-02 19:12:50 +0200 (Fri, 02 Jul 2010) | 11 lines
+
+Add OpenBSD support.
+Add a requirements section to the man page which lists the needed access
+permissions for each programmer.
+
+This feature needs my pciutils/libpci 8/16-bit write emulation patch at
+http://marc.info/?l=openbsd-ports&m=127780030728045 titled
+[PATCH] Fix pciutils non-32bit PCI write on OpenBSD
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stuart Henderson <sthen@openbsd.org>
+
+------------------------------------------------------------------------
+r1066 | hailfinger | 2010-07-01 19:45:54 +0200 (Thu, 01 Jul 2010) | 5 lines
+
+ICH9/10: display FRAP/FREGx access controls
+
+Signed-off-by: Joshua Roys <roysjosh@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1065 | hailfinger | 2010-07-01 13:16:28 +0200 (Thu, 01 Jul 2010) | 6 lines
+
+Add support for the HP DL165 G6.
+Change the match for the HP DL145 G3 to avoid matching on the DL165 G6.
+
+Signed-off-by: Arne Georg Gleditsch <arne.gleditsch@numascale.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1064 | mkarcher | 2010-06-29 16:44:40 +0200 (Tue, 29 Jun 2010) | 4 lines
+
+Check that the expected winbond Super I/O was found
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1063 | mkarcher | 2010-06-27 17:07:52 +0200 (Sun, 27 Jun 2010) | 4 lines
+
+Board enable for Asus A8N-VM CSM
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r1062 | mkarcher | 2010-06-27 17:07:49 +0200 (Sun, 27 Jun 2010) | 10 lines
+
+W83627x code unification
+
+This patch unifies the code for different Winbond W83627-family chips,
+to be applied before I add another W83627 GPIO raise function.
+
+After the Ack I added the check for unimplemented GPIO ports, but still
+dared to reuse the ack.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r1061 | hailfinger | 2010-06-25 15:18:48 +0200 (Fri, 25 Jun 2010) | 7 lines
+
+Work around shadowing warnings in libpci headers. This is needed for
+warning-free compilation on older gcc versions (3.x and probably older).
+Such a gcc version is the default on i386 OpenBSD.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stuart Henderson <sthen@openbsd.org>
+
+------------------------------------------------------------------------
+r1060 | hailfinger | 2010-06-24 13:51:12 +0200 (Thu, 24 Jun 2010) | 5 lines
+
+SST39VF010 tested, works.
+
+Signed-off-by: Guenter Knauf <lists@gknw.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1059 | hailfinger | 2010-06-24 13:39:57 +0200 (Thu, 24 Jun 2010) | 5 lines
+
+Add Winbond W25Q64 support. Tested.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1058 | hailfinger | 2010-06-24 01:14:44 +0200 (Thu, 24 Jun 2010) | 9 lines
+
+If flashrom is standalone and has no OS below, it can't call dmidecode.
+Provide empty DMI stubs for that case until someone implements our own
+dmidecode subset.
+
+Tested by Patrick Georgi on top of libpayload.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
+
+------------------------------------------------------------------------
+r1057 | hailfinger | 2010-06-22 01:20:15 +0200 (Tue, 22 Jun 2010) | 8 lines
+
+Kill unneeded #include wherever possible.
+
+Tested on Linux, FreeBSD, NetBSD, OpenBSD, DOS.
+Thanks to Jonathan A. Kollasch and Idwer Vollering for testing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer+lists.flashrom@gmail.com>
+
+------------------------------------------------------------------------
+r1056 | hailfinger | 2010-06-21 18:12:22 +0200 (Mon, 21 Jun 2010) | 5 lines
+
+Add support for Hyundai HY29F002 and HY29F002B.
+
+Signed-off-by: David Borg <borg.db@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1055 | hailfinger | 2010-06-20 13:04:26 +0200 (Sun, 20 Jun 2010) | 6 lines
+
+Fill in buses_supported for remaining Intel chipsets (ICH0-ICH5,
+Poulsbo).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1054 | hailfinger | 2010-06-20 13:02:33 +0200 (Sun, 20 Jun 2010) | 9 lines
+
+The SPI opcode 0xd8 is not a chip erase opcode on any chip out there.
+Besides that, the function as implemented just walks the chip and
+ignores sector sizes.
+Sector erase with SPI opcode 0xd8 is of course still supported.
+Kill a declaration for a nonexisting function while we're at it.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1053 | hailfinger | 2010-06-20 12:58:32 +0200 (Sun, 20 Jun 2010) | 6 lines
+
+Add SPI chip read support to the dummy flasher. This allows using the
+dummy flasher for SPI read debugging.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1052 | hailfinger | 2010-06-20 12:41:35 +0200 (Sun, 20 Jun 2010) | 7 lines
+
+Modernize SPI AAI code, blacklist IT87 SPI for AAI, allow AAI to run
+without warnings on ICH/VIA SPI.
+Add some code to make conversion to partial write possible for AAI.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1051 | hailfinger | 2010-06-20 12:39:33 +0200 (Sun, 20 Jun 2010) | 7 lines
+
+Fix message printing for SPI RES on spew level.
+Use a blacklist instead of a whitelist for 4-byte SPI RDID.
+Tell users where to report bugs.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1050 | mkarcher | 2010-06-20 00:06:35 +0200 (Sun, 20 Jun 2010) | 4 lines
+
+Add EMST F25L008A SPI chip
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r1049 | stuge | 2010-06-17 02:01:56 +0200 (Thu, 17 Jun 2010) | 7 lines
+
+Set maximum flash size for 3Com NICs to 128kb = 1Mbit
+
+This fact was already documented on http://flashrom.org/NIC3Com
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1048 | hailfinger | 2010-06-14 20:40:59 +0200 (Mon, 14 Jun 2010) | 10 lines
+
+Detect incompatible CONFIG_FOO=yes for the specified target and refuse
+to compile with a meaningful error message.
+Set the default for incompatible CONFIG_FOO to no.
+
+Just running "make" should result in a a build which compiles the common
+subset of available and working features.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer+lists.flashrom@gmail.com>
+
+------------------------------------------------------------------------
+r1047 | hailfinger | 2010-06-14 16:44:08 +0200 (Mon, 14 Jun 2010) | 7 lines
+
+Handle OS where executables have a hardcoded suffix, e.g. DOS with .exe
+This ensures that any temp files in the configure/check step of the
+Makefile are removed correctly.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer+flashrom@gmail.com>
+
+------------------------------------------------------------------------
+r1046 | hailfinger | 2010-06-14 16:18:37 +0200 (Mon, 14 Jun 2010) | 11 lines
+
+The nicrealtek code uses magic constants, but they are not explained.
+That's OK if you know the datasheet well, but for casual readers some
+comments are really helpful.
+
+I'm not sure whether we want to disable hardware flash access forever
+without enabling it again on shutdown. A few other places made me wonder
+as well. I've added FIXME comments in those places.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Andrew Morgan <ziltro@ziltro.com>
+
+------------------------------------------------------------------------
+r1045 | hailfinger | 2010-06-14 14:58:06 +0200 (Mon, 14 Jun 2010) | 7 lines
+
+Add SST25LF040A support.
+Checked against datasheets, should work.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1044 | hailfinger | 2010-06-14 14:42:05 +0200 (Mon, 14 Jun 2010) | 9 lines
+
+We already have NEED_PCI in the Makefile to link in PCI support. Add
+NEED_SERIAL and NEED_NET to decouple individual drivers from compilation
+and linking decisions.
+Move libgetopt from a DOS+PCI dependency to a DOS dependency to fix
+linking on DOS if no driver requiring PCI is enabled.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1043 | mkarcher | 2010-06-13 12:16:12 +0200 (Sun, 13 Jun 2010) | 13 lines
+
+VIA: disable byte merging
+
+All mentioned north bridges have been checked against data sheet. That's
+all north bridges google found a datasheet for with "byte merge" included.
+
+Runs multiple chipset enables if the first one requests further enables to
+be run.
+
+VIA byte-merging logic tested: works.
+multiple chipset logic: completely untested
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1042 | mkarcher | 2010-06-13 01:14:03 +0200 (Sun, 13 Jun 2010) | 6 lines
+
+Unbreak flashrom - fix compiler error (trivial)
+
+Fix compiler error (bad forward port in r1040).
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r1041 | mkarcher | 2010-06-13 01:07:26 +0200 (Sun, 13 Jun 2010) | 8 lines
+
+Board-enable for MS-7025 (K8N Neo2 Platinum)
+
+test report is
+http://www.coreboot.org/pipermail/flashrom/2010-April/002967.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Tested-by: Valentine "Pegasus rider" Yatsenko <mr.qweo@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1040 | mkarcher | 2010-06-12 19:27:44 +0200 (Sat, 12 Jun 2010) | 7 lines
+
+Board enable for EPIA EK (untested)
+
+Reporter/owner of that board: oscar <oshikore@gmail.com>
+http://www.coreboot.org/pipermail/flashrom/2010-April/002910.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1039 | hailfinger | 2010-06-08 00:37:54 +0200 (Tue, 08 Jun 2010) | 8 lines
+
+National Semiconductor DP83815/DP83816 and DP83820 NIC programmer
+support.
+Some instability remains, but that may be due to hardware problems in
+the specific card (Netgear FA311) used for testing.
+
+Signed-off-by: Andrew Morgan <ziltro@ziltro.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1038 | uwe | 2010-06-07 21:41:25 +0200 (Mon, 07 Jun 2010) | 21 lines
+
+Various manpage fixes and improvements.
+
+ - Use [<vendor>:]<board>], not [<vendor>:]<part>], which is more clear.
+
+ - Mention TSOP48 chips in the description.
+
+ - Highlight various additional parts in the manpage which were missing
+   so far (i.e., make them bold), including cmdline switches and others.
+
+ - Mention that you can use -VV.
+
+ - Fix name of the now-renamed 'Supported mainboards' section in -L output.
+
+ - Mention that ft2232_spi and buspirate_spi only support SPI chips.
+
+ - Readability and cosmetic improvements, add missing escapes, fix typos.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1037 | uwe | 2010-06-07 21:06:26 +0200 (Mon, 07 Jun 2010) | 11 lines
+
+board_enable.c: Remove useless 'name' parameter.
+
+Every board-enable function is passed a 'const char *name' (board name)
+which is totally useless as the board name was already printed by flashrom
+at that point. Also, 95% or so of the board-enables don't use the
+parameter anyway. So, drop it.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1036 | hailfinger | 2010-06-07 16:10:55 +0200 (Mon, 07 Jun 2010) | 5 lines
+
+Support Atmel AT49F020 256kB parallel flash.
+
+Signed-off-by: Andrew Morgan <ziltro@ziltro.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1035 | hailfinger | 2010-06-07 13:10:43 +0200 (Mon, 07 Jun 2010) | 7 lines
+
+Fix wiki board enable parameter printing. The logic was incorrect in one
+place which had && instead of ||.
+Move the board info #define B to the file where it is used.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1034 | hailfinger | 2010-06-07 13:08:07 +0200 (Mon, 07 Jun 2010) | 5 lines
+
+Create dependencies on the fly rather than in a separate step.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1033 | hailfinger | 2010-06-05 01:24:57 +0200 (Sat, 05 Jun 2010) | 10 lines
+
+NetBSD needs libpciutils (which is called libpci on pretty much every
+other platform and lives in the pciutils package) and apparently the
+libpciutils on NetBSD needs the NetBSD-native libpci (no equivalent on
+other platforms).
+
+Thanks to Jonathan A. Kollasch for reporting.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Jonathan A. Kollasch <jakllsch@kollasch.net>
+
+------------------------------------------------------------------------
+r1032 | hailfinger | 2010-06-05 01:20:21 +0200 (Sat, 05 Jun 2010) | 9 lines
+
+gcc and clang can check format strings of printf-like functions. Since
+we don't support any other compilers right now, enable that extension
+unconditionally.
+
+Fix the bugs found by format string checking.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r1031 | hailfinger | 2010-06-04 21:05:39 +0200 (Fri, 04 Jun 2010) | 10 lines
+
+The internal programmer needs correct information about flash_base and
+chip window top/bottom alignment on non-x86 before it can be used.
+Abort any internal programmer action for now until the code is fixed.
+
+Add the concept of a processor enable for systems where flashing is
+impacted by processor settings or processor model.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1030 | uwe | 2010-06-04 19:07:39 +0200 (Fri, 04 Jun 2010) | 17 lines
+
+Make the 'flashrom --help' output look a bit nicer.
+
+Only print "flashrom" as the program name unconditionally, not the full path
+and program name (e.g. "/home/foo/bar/baz/flashrom" or on Windows
+"C:\Foo\Bar\Whatever\flashrom.exe"). The path or exact executable name is
+not really useful to print here, if you managed to run --help you already
+know it, and it just makes the output look ugly.
+
+Also, add a missing newline to make the output look nicer.
+
+Finally, revert the "CONFIG_PRINT_WIKI ?= yes" change which accidentally
+slipped into r1029.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1029 | uwe | 2010-06-04 18:39:35 +0200 (Fri, 04 Jun 2010) | 6 lines
+
+Fix URLs for GIGABYTE motherboards.
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1028 | hailfinger | 2010-06-03 23:48:13 +0200 (Thu, 03 Jun 2010) | 15 lines
+
+Do not trust the OS at all and measure timer precision before
+calibrating the delay loop and use that measurement to get reasonable
+precision for our own delay code.
+
+Print a measurement for a delay of 4x the OS timer resolution.
+
+Be precise about how bad the deviation was if we had to recalculate.
+
+Tested on Windows XP, 32 bit, built using MinGW by Uwe.
+Tested on FreeDOS v1.0 Final, 32bit, built using DJGPP 4.3.2 by Idwer.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Idwer Vollering <vidwer+lists.flashrom@gmail.com>
+
+------------------------------------------------------------------------
+r1027 | uwe | 2010-06-03 18:35:51 +0200 (Thu, 03 Jun 2010) | 9 lines
+
+Fix bug in wiki printing and whitespace (trivial).
+
+The required "-m" options were not in the wiki output due to a mistake
+that I think I introduced recently.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1026 | hailfinger | 2010-06-03 02:49:50 +0200 (Thu, 03 Jun 2010) | 6 lines
+
+Fix fallout from r1021 which caused compile failures if only the dummy
+programmer was selected.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1025 | mkarcher | 2010-06-01 18:09:06 +0200 (Tue, 01 Jun 2010) | 8 lines
+
+Add hp xw9400 board enable.
+
+Also modifies nvidia_mcp_gpio_set to cope with multiple MCP55 chips on
+the same board, like on the Tyan S2915-E.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Adis Salcin <crow@linux.org.ba>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r1024 | uwe | 2010-06-01 12:13:17 +0200 (Tue, 01 Jun 2010) | 9 lines
+
+Merge print.c and print_wiki.c board/URL tables.
+
+Also, merge the tables in the output, i.e. there's only one table which
+contains both known-good and known-bad/untested boards.
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1023 | hailfinger | 2010-05-31 17:27:27 +0200 (Mon, 31 May 2010) | 18 lines
+
+So far, we have up to 4 different names for the same thing (ignoring
+capitalization):
+CONFIG_FT2232SPI (makefile config option)
+FT2232_SPI_SUPPORT (#define)
+ft2232spi (programmer name)
+ft2232_spi.c (programmer file)
+
+Use CONFIG_* with underscores for makefile config options and #defines
+and kill the useless _SUPPORT idiom.
+Use lowercase names with underscores for programmer names and programmer
+files.
+
+With this, you can run "grep -i ft2232_spi" and find everything related
+to the ft2232_spi driver. Same applies to all other programmers.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1022 | hailfinger | 2010-05-31 00:35:14 +0200 (Mon, 31 May 2010) | 8 lines
+
+Add flashrom.exe unconditionally to the list of files removed at make
+clean. This allows users to run make clean without specifying the target
+architecture.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1021 | hailfinger | 2010-05-31 00:24:40 +0200 (Mon, 31 May 2010) | 13 lines
+
+Remove unneeded #include statements completely.
+
+unistd.h was only used to get a definition of NULL in all files. Add our
+own NULL #define and remove unistd.h from flash.h
+stdio.h has no place in flash.h, it should be included only in files
+which really need it.
+Add #include statements in individual .c files where needed.
+
+Replace a few printf with msg_* to eliminate the need for stdio.h.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1020 | uwe | 2010-05-30 19:50:16 +0200 (Sun, 30 May 2010) | 10 lines
+
+Mark the following chip as supported:
+
+ - Winbond W39V040FA (reported by Guenter <lists@gknw.net>)
+   Read (thus also probe), write (thus also erase), and verify tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003078.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1019 | uwe | 2010-05-30 19:00:19 +0200 (Sun, 30 May 2010) | 40 lines
+
+Update the status for the following chips:
+
+ - Eon EN25F80 (reported by oops66 <oops66@wanadoo.fr>)
+   Probe and read tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003183.html
+
+ - AMIC A49LF040A (reported by Guenter <lists@gknw.net>)
+   Read (thus also probe), write (thus also erase), and verify tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003078.html
+   Also reported by Robert Grasso <robert.grasso@modulonet.fr>.
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003006.html
+
+ - SST SST49LF008A (reported by Marco Giacinti <marcogiacinti@hotmail.it>)
+   Erase tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-May/003010.html
+
+ - SST SST29EE020A (reported by Anders Jenbo <anders@jenbo.dk>)
+   Write (and thus erase) tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-April/002961.html
+
+ - SST SST49LF040 (reported by David Westberg <david@uarda.dlinkddns.com>)
+   Probe and read tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-April/002862.html
+
+ - Winbond W39V080FA (reported by Maciej ?\197?\187enczykowski <zenczykowski@gmail.com>)
+   All operations tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-April/002863.html
+
+ - Winbond W29C020C (reported by Urja Rannikko <urjaman@gmail.com>)
+   Erase tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-April/002847.html
+
+ - PMC Pm39LV010 (reported by Tim Small <tim@seoss.co.uk>)
+   Write (and thus also erase) tested.
+   http://www.flashrom.org/pipermail/flashrom/2010-March/002711.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1018 | mkarcher | 2010-05-30 18:55:18 +0200 (Sun, 30 May 2010) | 4 lines
+
+Unlocking for W39V040FA
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r1017 | hailfinger | 2010-05-28 19:07:57 +0200 (Fri, 28 May 2010) | 8 lines
+
+Some chips implement the RES (0xab) opcode, but they use a non-standard
+two byte response instead of the usual one byte response.
+A two-byte response has the accuracy of REMS and RDID, so don't check
+for REMS/RDID availability before running a two-byte RES.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r1016 | hailfinger | 2010-05-28 17:53:08 +0200 (Fri, 28 May 2010) | 11 lines
+
+ICH SPI can enforce address restrictions for all accesses which take an
+address (well, it could if the chipset implementation was not broken).
+Since exploiting the broken implementation is harder than conforming to
+the address restrictions wherever possible, conform to the address
+restrictions instead.
+This patch eliminates a lot of transaction errors people were seeing
+on chip probe.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r1015 | uwe | 2010-05-27 00:29:51 +0200 (Thu, 27 May 2010) | 9 lines
+
+It seems that this board is actually a 'Pro' version. At least it's
+addressed as 'Pro' in the list of boards, which requires board_enable.
+
+See also: http://www.flashrom.org/pipermail/flashrom/2009-July/000003.html
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1014 | uwe | 2010-05-27 00:26:44 +0200 (Thu, 27 May 2010) | 6 lines
+
+Sort boards in board-enable table alphabetically.
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1013 | hailfinger | 2010-05-26 03:45:41 +0200 (Wed, 26 May 2010) | 39 lines
+
+Handle the following architectures in generic flashrom code:
+- x86/x86_64 (little endian)
+- PowerPC (big endian)
+- MIPS (big+little endian)
+
+No changes to programmer specific code. This means any drivers with MMIO
+access will _not_ suddenly start working on big endian systems, but with
+this patch everything is in place to fix them.
+
+Compilation should work on all architectures listed above for all
+drivers except nic3com and nicrealtek which require PCI Port IO which is
+x86-only for now.
+
+To compile without nic3com and nicrealtek, run
+make distclean
+make CONFIG_NIC3COM=no CONFIG_NICREALTEK=no
+
+
+Thanks to Misha Manulis for testing early versions of this patch on
+PowerPC (big endian) with the satasii programmer.
+Thanks to Segher Boessenkool for design review and for helping out with
+compiler tricks and pointing out that we need eieio on PowerPC.
+Thanks to Vladimir Serbinenko for compile testing on MIPS (little
+endian) and PowerPC (big endian) and for runtime testing on MIPS (little
+endian).
+Thanks to David Daney for compile testing on MIPS (big endian).
+Thanks to Uwe Hermann for compile and runtime testing on x86_64.
+
+DO NOT RUN FLASHROM ON NON-X86 AFTER APPLYING THIS PATCH!
+This patch only provides the infrastructure, but does not convert any
+drivers, so flashrom will compile, but it won't do the right thing on
+non-x86 platforms.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Misha Manulis <misha@manulis.com>
+Acked-by: Vladimir 'phcoder/?\207?\134-coder' Serbinenko <phcoder@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Segher Boessenkool <segher@kernel.crashing.org>
+
+------------------------------------------------------------------------
+r1012 | uwe | 2010-05-26 01:27:44 +0200 (Wed, 26 May 2010) | 17 lines
+
+Mark the following chips as OK:
+
+ - PMC Pm49FL004
+ - SST SST49LF020
+ - SST SST49LF020A
+ - SST SST49LF040B
+ - SST SST49LF080A
+ - Winbond W39V040B
+
+I tested all operations on hardware using r997. Only on SST49LF040B
+write/erase does not seem to work, will investigate later (probe/read
+works, though).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r1011 | uwe | 2010-05-24 19:39:14 +0200 (Mon, 24 May 2010) | 12 lines
+
+Various nicrealtek fixes:
+
+ - Add missing entries for 'flashrom -L' output and wiki output.
+
+ - Add missing entries in the manpage.
+
+ - nicrealtek.c: Coding style fixes and cosmetics.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1010 | mkarcher | 2010-05-24 18:03:57 +0200 (Mon, 24 May 2010) | 4 lines
+
+Board enable for IP530
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Marc Bertens <mbertens@xs4all.nl>
+------------------------------------------------------------------------
+r1009 | uwe | 2010-05-24 17:28:12 +0200 (Mon, 24 May 2010) | 18 lines
+
+Various wiki output improvements as per IRC discussion (trivial).
+
+ - Use '?3' wiki template (light greenish, not gray) for untested stuff.
+ - Reduce page width a bit to improve readability on smaller screens.
+ - Generalize some functions a bit (pass in how many columns to generate).
+ - Mark untested board-enables as such (were incorrectly marked "OK" so far).
+ - Drop some useless 'valign=top' entries.
+ - Make a few more functions 'static' while we're at it.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r1008 | hailfinger | 2010-05-22 09:31:50 +0200 (Sat, 22 May 2010) | 8 lines
+
+Add debug output of the exact matched chipset PCI ID to keep track of
+tested PCI IDs for chipsets with one name and multiple IDs.
+This will help avoid problems similar to the Tyan S2915 OEM undetected
+flash in the future.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1007 | hailfinger | 2010-05-22 09:27:16 +0200 (Sat, 22 May 2010) | 13 lines
+
+Fix Tyan S2915 OEM board by commenting out MCP55 LPC bridge PCI ID
+10de:0361 which is the secondary LPC bridge. The same effect could be
+achieved by refusing to run enable_flash_mcp55 if the device class is
+not ISA bridge [0601].
+
+Thanks to Alessandro Polverini, Joel Robertson, Nicolas Aveline,
+Phil LoCascio and Nils-Helge Garli Hegvik for testing flashrom on
+hardware and Michael Karcher for analyzing the factory BIOS for clues.
+In the end, no board enable was needed and it was a pure chipset issue.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1006 | hailfinger | 2010-05-22 09:10:46 +0200 (Sat, 22 May 2010) | 6 lines
+
+Initialize the internal delay function before running programmer init.
+The programmer init may need a good host delay function.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r1005 | hailfinger | 2010-05-22 01:09:42 +0200 (Sat, 22 May 2010) | 12 lines
+
+Every SPI programmer driver had its own completely different chip write
+implementation, and all of them were insufficiently commented.
+Create spi_write_chunked as a copy of spi_read_chunked and convert all
+SPI programmers to use it.
+No functional changes except:
+- Bus Pirate uses 12 Byte writes instead of 8 Byte writes
+- SB600 uses 5 Byte writes instead of 1 Byte writes
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r1004 | hailfinger | 2010-05-22 01:00:56 +0200 (Sat, 22 May 2010) | 6 lines
+
+libpci < 2.2.4 can not store class info in struct pci_dev.
+Read class info manually and store it in a separate variable.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r1003 | hailfinger | 2010-05-22 00:28:19 +0200 (Sat, 22 May 2010) | 7 lines
+
+Add missing nicrealtek.c which was missing from revision 1002 which was
+
+Support for Realtek RTL8139 network card flashing.
+
+Signed-off-by: Joerg Fischer <turboj@gmx.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1002 | hailfinger | 2010-05-21 23:54:07 +0200 (Fri, 21 May 2010) | 5 lines
+
+Support for Realtek RTL8139 network card flashing.
+
+Signed-off-by: Joerg Fischer <turboj@gmx.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r1000 | hailfinger | 2010-05-19 18:46:52 +0200 (Wed, 19 May 2010) | 8 lines
+
+Increase flashrom release number to 0.9.2.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r999 | mkarcher | 2010-05-18 01:19:22 +0200 (Tue, 18 May 2010) | 6 lines
+
+msr_t memory layout may depend on compiler; with optimizations this
+may lead to writing incorrect data to MSR.
+Create a temporary buffer with correct layout to avoid this problem.
+
+Signed-off-by: Anti Sullin <anti.sullin@artecdesign.ee>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r998 | hailfinger | 2010-05-15 17:04:37 +0200 (Sat, 15 May 2010) | 7 lines
+
+Fix assorted documentation, frontend and printing bugs.
+Change the command line interface to make file names positional.
+Add more sanity checks to the command line parser.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r997 | snelson | 2010-05-07 22:09:04 +0200 (Fri, 07 May 2010) | 8 lines
+
+convert programmer print messages to msg_p*
+convert general print messages to msg_g*
+a few fixes as suggested by Carl-Daniel
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r996 | hailfinger | 2010-04-28 17:22:14 +0200 (Wed, 28 Apr 2010) | 37 lines
+
+--force may have been a good idea back when only developers were using
+flashrom, but over the last few months we've seen too many people who
+incorrectly believed that --force would solve anything.
+
+One of the problems is that --force had multiple meanings:
+- Force chip read by faking probe success.
+- Force chip access even if the chip is bigger than max decode size for
+  the flash bus.
+- Force erase even if erase is known bad.
+- Force write even if write is known bad.
+- Force writing even if cbtable tells us that this is the wrong image
+  for this board.
+
+This patch cleans up --force usage:
+- Remove any suggestions to use --force for probe/read from flashrom
+  output.
+- Don't talk about "success" or "Found chip" if the chip is forced.
+- Add a new internal programmer parameter boardmismatch=force. This
+  overrides any mismatch detection from cbtable/image comparisons.
+- Add a new internal programmer parameter laptop=force_I_want_a_brick.
+- Adjust the documentation for --force.
+- Clean up the man page a bit whereever it talks about --force or
+  laptops.
+
+Additional changes in this patch:
+- Add warnings about laptops to the documentation.
+- Abort if a laptop is detected. Can be overridden with the programmer
+parameter mentioned above.
+- Add "Portable" to the list of DMI strings indicating laptops.
+- Check if a chip specified with -c is known to flashrom.
+- Programmer parameter reliability and consistency fixes.
+- More paranoid self-checks.
+- Improve documentation.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r995 | ruik | 2010-04-26 00:47:50 +0200 (Mon, 26 Apr 2010) | 9 lines
+
+
+Fix the DOS port. Now the DS selector limit is set to 4GB and all mmio accesses goes through DS, 
+the 1:1 mapping is fixed so the _DS base is taken onto account. Plus is that the hwaccess.c needs
+no change and memcpy etc can be used on mmaped space.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz> 
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r994 | ruik | 2010-04-20 21:34:31 +0200 (Tue, 20 Apr 2010) | 9 lines
+
+
+I added following Winbond chips:
+
+W25Q80, W25Q16 and W25Q32. I tested read/write/probe with W25Q80.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz> 
+Acked-by: David Hendricks <dhendrix@google.com>
+
+
+------------------------------------------------------------------------
+r993 | mkarcher | 2010-04-11 23:01:06 +0200 (Sun, 11 Apr 2010) | 5 lines
+
+Add board enable for ABit NF7-S
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Tom Brand <worntreads@sbcglobal.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r992 | hailfinger | 2010-04-09 02:02:38 +0200 (Fri, 09 Apr 2010) | 6 lines
+
+Reinitialize the delay loop upon recalibration.
+Fix an unescaped % in a format specifier.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r991 | mkarcher | 2010-04-03 12:27:08 +0200 (Sat, 03 Apr 2010) | 14 lines
+
+Intel 28F004/28F400 support
+
+Remove blockwise write for i82802ab chips. It will be reintroduced
+in post-0.9.2 in a generic way. This is needed to fix
+FWH-like chips with non-uniform sectors.
+
+These are:
+  Intel 28F001
+  Sharp LHF00L04
+  ST M50FW002
+  ST M50LPW116
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r990 | hailfinger | 2010-04-01 01:55:06 +0200 (Thu, 01 Apr 2010) | 37 lines
+
+The current delay loop calculation is still from revision 1 of flashrom,
+and since then it had a logic bug which caused all delays to be twice as
+long as intended. Fix the delay duration.
+
+Protect against delay loop overflows.
+
+Detect a non-working delay loop.
+
+Change the delay loop itself to ensure clever compiler optimizers won't
+eliminate it (as happens with clang/llvm in the current code). Some
+people suggested machine-specific asm, but the empty asm statement with
+the loop counter as register/memory input has the benefit of being
+perfectly cross-platform and working in gcc and clang.
+
+If time goes backwards (catastrophical NTP time difference, manual time
+change), timing measurements were shot because the new-old time
+subtraction yielded negative numbers which weren't handled correctly
+because the variable is unsigned. Work around that issue (a fix is
+mathematically impossible).
+
+If time goes forward too fast, pick the biggest possible timing
+measurement with a guaranteed overflow avoidance for all timing
+calculations.
+
+Check four times if the calculated timing is at most 10% too fast. This
+addresses OS scheduler interactions, e.g. being scheduled out during
+measurement which inflates measurements.
+
+If the timing looks like garbage, recalculate the timer values up to
+four times before giving up.
+
+Avoid division by zero in rare cases where timing measurements for a 250
+ms delay returned 0 us elapsed.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+
+------------------------------------------------------------------------
+r989 | hailfinger | 2010-03-30 04:45:18 +0200 (Tue, 30 Mar 2010) | 8 lines
+
+Add ITE IT8720 SPI support.
+Original patch by Vadim Girlin.
+Message printing updated by Carl-Daniel Hailfinger.
+
+Signed-off-by: Vadim Girlin <vadimgirlin@gmail.com>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r988 | hailfinger | 2010-03-28 00:25:14 +0100 (Sun, 28 Mar 2010) | 5 lines
+
+Add PMC Pm39LV020 and Pm39LV040.
+
+Signed-off-by: Anders Juel Jensen <andersjjensen@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r987 | hailfinger | 2010-03-27 17:36:40 +0100 (Sat, 27 Mar 2010) | 40 lines
+
+Add runtime and build environment info to the flashrom version message.
+This patch uses code from Idwer Vollering and Maciej Pijanka.
+I've added Makefile support and compiler version printing and
+restructured the code heavily.
+The code prints runtime system information and buildtime libpci
+information (I couldn't find any runtime libpci version function). Due
+to our ability to cross-compile flashrom, buildtime system information
+from "uname -mrs" doesn't help diagnosing any problems. That's why only
+libpci and gcc are buildtime info, and the rest is runtime info.
+
+Examples:
+
+openSUSE 10.3, i686, gcc 4.2.1, with PCI support:
+flashrom v0.9.1-r971 on Linux 2.6.22.19-0.2-default (i686), built with
+libpci 2.2.6, GCC 4.2.1 (SUSE Linux)
+
+openSUSE 10.3, i686, llvm-clang-2.6.99svn97231, with PCI support:
+flashrom v0.9.1-r971 on Linux 2.6.22.19-0.2-default (i686), built with
+libpci 2.2.6, LLVM 1/clang 1
+
+openSUSE 11.1, x86_64, gcc 4.3.2, with PCI support:
+flashrom v0.9.1-r972 on Linux 2.6.27.29-0.1-default (x86_64), built with
+libpci 3.0.1, GCC 4.3.2 [gcc-4_3-branch revision 141291]
+
+openSUSE 10.3, i686, gcc 4.2.1, without PCI support:
+flashrom v0.9.1-r971 on Linux 2.6.22.19-0.2-default (i686), built with
+GCC 4.2.1 (SUSE Linux)
+
+Windows/cygwin, i686, gcc 4.3.4, without PCI support:
+flashrom v0.9.1-r973 on CYGWIN_NT-5.1 1.7.1(0.218/5/3) (i686), built
+with GCC 4.3.4 20090804 (release) 1
+
+FreeBSD 8.0, i386, gcc 4.2.1, with PCI support:
+flashrom v0.9.1-r973 on FreeBSD 8.0-RELEASE-p2 (i386), built with libpci
+3.1.7, GCC 4.2.1 20070719  [FreeBSD]
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+
+------------------------------------------------------------------------
+r986 | hailfinger | 2010-03-27 17:16:01 +0100 (Sat, 27 Mar 2010) | 7 lines
+
+The delay loop is probably one of the oldest pieces of code in flashrom.
+Clean up code duplication and measure timing of 10/100/1000/10000 us
+delays.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+
+------------------------------------------------------------------------
+r985 | uwe | 2010-03-26 00:18:41 +0100 (Fri, 26 Mar 2010) | 10 lines
+
+Polish the flashrom code comments and outputs a bit.
+
+ - Fix a number of typos (found via ispell).
+
+ - Use correct vendor names (as per their websites) consistently.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r984 | mkarcher | 2010-03-25 10:23:46 +0100 (Thu, 25 Mar 2010) | 41 lines
+
+Add success reports
+
+PMC Pm39LV010:
+ See http://www.coreboot.org/pipermail/flashrom/2010-March/002711.html
+ Thanks to Tim Small for reporting!
+
+Supermicro X8DTT-F:
+ See http://www.coreboot.org/pipermail/flashrom/2010-March/002707.html
+ Thank to Taylan Develioglu for testing!
+
+Gigabyte GA-965P-DS4:
+ See http://www.coreboot.org/pipermail/flashrom/2010-March/002426.html
+ Thanks to Michal Andrzejczak for reporting!
+
+Tyan Tempest i5000PW:
+ See http://www.coreboot.org/pipermail/flashrom/2010-February/002358.html
+ Thanks to Rob Lazzurs for reporting!
+
+PCEngines WRAP.2E:
+ See http://www.coreboot.org/pipermail/flashrom/2010-February/002187.html
+ Thanks to Vincenzo Caruso for testing!
+
+Asus P5B:
+ This board has been reporting as working (for r710/0.9.1) in:
+ http://www.coreboot.org/pipermail/flashrom/2010-February/002170.html
+ Thanks to Patrice Levesque for testing!
+
+MSI 7312 (K9MM-V) + W39V040B:
+ See http://www.coreboot.org/pipermail/flashrom/2010-February/002159.html
+ Thanks to David Mears for testing!
+
+Probe + Read on SST49LF080A:
+ See http://www.coreboot.org/pipermail/flashrom/2010-February/002095.html
+ Thanks to Peter Lemenkov for testing!
+
+Finally:
+ remove Asus A7V8X-X from "boards_ok", as this table is meant only for
+ boards not needing a board enable.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r983 | hailfinger | 2010-03-25 03:50:40 +0100 (Thu, 25 Mar 2010) | 20 lines
+
+Autodetect ITE IT87* LPC->SPI translation on all boards without the need
+for a board enable.
+Move boards which had an IT87* SPI board enable from the board enable
+list to the OK list.
+
+Mark the Gigabyte GA-MA78GPM-DS2H as OK.
+
+Change the it87spi forced port parameter to it87spiport=...
+
+Fix incorrect indentation in the man page.
+
+Tested by Ward Vandewege on both variants of the Gigabyte GA-M57SLI-S4
+http://www.flashrom.org/pipermail/flashrom/2010-March/002712.html
+
+Tested by ?\230?\157?\142?\229?\189?\165?\229?\173?\184 (Ian-Xue Li) on the Gigabyte GA-MA78GPM-DS2H
+http://www.flashrom.org/pipermail/flashrom/2010-March/002723.html
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r982 | snelson | 2010-03-25 00:14:32 +0100 (Thu, 25 Mar 2010) | 7 lines
+
+Convert chips' message printing to msg_c*
+Fixed suggestions by Carl-Daniel.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r981 | mkarcher | 2010-03-25 00:10:01 +0100 (Thu, 25 Mar 2010) | 4 lines
+
+Fix copy/paste error in print.c preventing compilation
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r980 | mkarcher | 2010-03-24 23:56:23 +0100 (Wed, 24 Mar 2010) | 8 lines
+
+Flashrom works on Acer Aspire 1520 (Laptop) with W39V040A
+
+See http://www.coreboot.org/pipermail/flashrom/2010-March/002451.html
+
+Thanks to Pawe?\197?\130 Stawicki for reporting!
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r979 | mkarcher | 2010-03-24 23:56:19 +0100 (Wed, 24 Mar 2010) | 9 lines
+
+Shuttle FD37 and MSI K9A2 Platinum are supported
+
+FD37: http://www.coreboot.org/pipermail/flashrom/2010-March/002440.html
+K9A2: http://www.coreboot.org/pipermail/flashrom/2010-March/002433.html
+
+Thanks to Sylvain BERTRAND for reporting!
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r978 | mkarcher | 2010-03-24 23:56:14 +0100 (Wed, 24 Mar 2010) | 12 lines
+
+MSI MS6330 tested with W49F002U and EN29F002
+
+W49F002U: http://www.coreboot.org/pipermail/flashrom/2010-March/002469.html
+EN29F002: http://www.coreboot.org/pipermail/flashrom/2010-March/002480.html
+
+Block erase was broken, chip erase worked, block erase is fixed in r934 but
+has not been tested since.
+
+Thanks to Guy Lacroix for reporting!
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r977 | mkarcher | 2010-03-24 23:56:08 +0100 (Wed, 24 Mar 2010) | 7 lines
+
+ASUS P6T Deluxe is OK
+
+See http://www.coreboot.org/pipermail/flashrom/2010-March/002501.html
+Thanks to Konstantin Matuschek for reporting.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r976 | mkarcher | 2010-03-24 23:56:02 +0100 (Wed, 24 Mar 2010) | 13 lines
+
+Clean up manufacturer mainboard links.
+
+The Asus A8NE-FM/S does exist, you find original ASUS pdf manuals in the
+internet, but seems to be an OEM board that is not documented on the
+Asus page.
+
+A lot of MSI boards are OEM boards that have no page at the MSI site...
+
+This patch also adds links in the Wiki for boards from the board enable
+table.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r975 | mkarcher | 2010-03-24 23:55:56 +0100 (Wed, 24 Mar 2010) | 14 lines
+
+Abit VT6X4 + Winbond W29C020C and Asus A7V133 + Atmel AT29C010A work
+
+Abit VT6X4 / W29C020C: See
+  http://www.coreboot.org/pipermail/flashrom/2010-March/002730.html
+  Fixes typo in comment and marks board-enable as tested (the flashrom
+  running on that machine was patched with the board enable that got
+  in later).
+
+Asus A7V133 / Atmel AT29C010A: See
+  http://www.coreboot.org/pipermail/flashrom/2010-March/002729.html
+  Adding "erase" to tested as there is only one erase function.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r974 | mkarcher | 2010-03-24 23:55:50 +0100 (Wed, 24 Mar 2010) | 7 lines
+
+Probe/Read tested for SST29EE020A
+
+http://www.flashrom.org/pipermail/flashrom/2010-February/002318.html
+Thanks to Andre Robatino for reporting!
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r973 | mkarcher | 2010-03-24 18:55:04 +0100 (Wed, 24 Mar 2010) | 4 lines
+
+Fix handling of empty dmidecode output
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r972 | snelson | 2010-03-23 18:10:28 +0100 (Tue, 23 Mar 2010) | 12 lines
+
+Sst49lfxxxc chips are functionally the same as 82802ab chips.
+Sst49lfxxxc software status register is functionally the same as the 
+82802ab status register, "Block Protect Status"(49lfxxxc) can be treated 
+the same as "Device Protect Status"(82802ab).
+Erase_block_49lfxxxc is the same command sequence as erase_block_82802ab.
+Add unlock_49lfxxxc to chips definitions.
+Write_sector_49lfxxxc is the same as write_page_82802ab.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r971 | hailfinger | 2010-03-23 00:47:38 +0100 (Tue, 23 Mar 2010) | 18 lines
+
+JEDEC ID probing checks the parity of the vendor ID and verifies that
+the ID differs from the flash chip contents.
+Add the same feature to 82802AB ID probing.
+
+This should reduce the number of lines we have to look at to determine
+if we're missing a chip definition or if we need a board enable. Just
+use grep on the log:
+grep -v "parity violation"
+To narrow it down further, try:
+grep -v "id1 is normal flash content, id2 is normal flash content"
+And of course you want to ignore the skipped probes:
+grep -v "skipped"
+The remaining lines are worth examining, and if those look bogus as
+well, you can bet that we just need a board enable.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r970 | hailfinger | 2010-03-23 00:43:51 +0100 (Tue, 23 Mar 2010) | 16 lines
+
+Reduce message severity level for skipped chips.
+
+Old verbose log excerpt:
+Probing for Atmel AT25DF021, 256 KB: skipped. Host bus type Parallel and
+chip bus type SPI are incompatible.
+
+New verbose log excerpt:
+Probing for Atmel AT25DF021, 256 KB: skipped.
+
+This makes logs more readable and manageable. If someone really
+desperately wants all the bus debugging stuff, he/she can switch to SPEW
+mode instead of VERBOSE mode.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-By: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r969 | snelson | 2010-03-22 22:48:51 +0100 (Mon, 22 Mar 2010) | 6 lines
+
+Clang complains loudly when there are duplicate printlock_sst_fwhub, gcc ignores them. Ack via IRC.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r968 | hailfinger | 2010-03-22 13:29:45 +0100 (Mon, 22 Mar 2010) | 13 lines
+
+Idwer Vollering reported problems with the current libpci check on
+FreeBSD 8.0-RELEASE i386
+This is caused by a strict linker. Parsing linker error messages is an
+exercise in futility, and library detection with
+$CC --print-file-name
+is totally useless for libraries outside the standard hardcoded builtin
+gcc search path (probably the same for other compilers as well).
+
+Look for libpciutils instead of libpci on NetBSD during the check.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r967 | snelson | 2010-03-22 08:03:26 +0100 (Mon, 22 Mar 2010) | 5 lines
+
+in unlock_28f004s5, variable 'i' needs to be int...
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r966 | snelson | 2010-03-22 07:57:02 +0100 (Mon, 22 Mar 2010) | 5 lines
+
+fix a few typos from the last commit.
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r965 | snelson | 2010-03-22 05:39:31 +0100 (Mon, 22 Mar 2010) | 10 lines
+
+To access/read the lock bits, we use the same mode to read the chip id.
+
+This patch looks into the write situation for the Intel 28F001BX-{B,T}. Looks like they're just a 82802ab page write.
+
+Unlock_28f004s5 has been changed to read all the lock bits and if at least one of the block lock bits are set, clear them all. If the master lock bit is set, we can't do anything about it, so we return.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger<c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r964 | hailfinger | 2010-03-22 04:30:58 +0100 (Mon, 22 Mar 2010) | 4 lines
+
+Multibyte SPI write for the Bus Pirate.
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r963 | hailfinger | 2010-03-21 15:54:57 +0100 (Sun, 21 Mar 2010) | 6 lines
+
+Add DOS cross-compilation support to the Makefile.
+Add a README with build instructions.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Rudolf Marek <r.marek@assembler.cz>
+
+------------------------------------------------------------------------
+r962 | mkarcher | 2010-03-21 14:36:20 +0100 (Sun, 21 Mar 2010) | 4 lines
+
+Adds board enable to Termtek TK-3370 thin client motherboard.
+
+Signed-off-by: Daniel Brandt <dbr@mindglow.se>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r961 | snelson | 2010-03-20 16:15:36 +0100 (Sat, 20 Mar 2010) | 7 lines
+
+unlock fixup
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+
+
+------------------------------------------------------------------------
+r960 | snelson | 2010-03-20 04:01:19 +0100 (Sat, 20 Mar 2010) | 7 lines
+
+The Intel 28F001BX-T/B chips don't have block locks or mention of registers; chip is Old.
+The Intel 28F004S5 mentions block locks which require a remapping registers.
+Fixes problems brought up by carldani because of commit r948.
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r959 | snelson | 2010-03-20 00:01:34 +0100 (Sat, 20 Mar 2010) | 6 lines
+
+Rebased Board Enable Patch: iBase MB899.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r958 | snelson | 2010-03-20 00:00:07 +0100 (Sat, 20 Mar 2010) | 8 lines
+
+Rebased Board Enable Patch: Abit AN-M2.
+
+Original patch by: Luc Verhaegen.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r957 | snelson | 2010-03-19 23:58:15 +0100 (Fri, 19 Mar 2010) | 11 lines
+
+Reversed-engineered board enable for the ASUS A8N-LA.
+Rebased.
+IDs are ISA and SMBus.
+Added dmi string to match 3 HP boards: Nagami, Nagami2, Nagami2L.
+
+This could match any HP Nagami board. Needs testing.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r956 | snelson | 2010-03-19 23:55:48 +0100 (Fri, 19 Mar 2010) | 11 lines
+
+Rebased Board Enable Patch: 2nd attempt to fix board detection on GA-MA74GM-S2H.
+
+This board (GA-MA74GM-S2H) has the same list of pciids as the GA-MA78M-S2H,
+so I narroved search conditions by populating corresponding board_pciid_enable
+entry for GA-MA78M-S2H with DMI pattern.
+
+Untested!
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r955 | snelson | 2010-03-19 23:52:00 +0100 (Fri, 19 Mar 2010) | 5 lines
+
+Rebased Board Enable Patch: Asus P4B533-E
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r954 | snelson | 2010-03-19 23:49:09 +0100 (Fri, 19 Mar 2010) | 7 lines
+
+Rebased Board Enable Patch: Factor out Via Apollo GPO setting
+VT6X4 actually depended on this commit, blame snelson.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r953 | snelson | 2010-03-19 23:39:24 +0100 (Fri, 19 Mar 2010) | 5 lines
+
+Rebased Board Enable Patch: A8JM board_enable patch
+Signed-off-by: James Lancaster <deathstalker@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r952 | snelson | 2010-03-19 23:37:29 +0100 (Fri, 19 Mar 2010) | 8 lines
+
+Rebased Board Enable Patch: Abit KN8 Ultra
+
+patch by Chris <zinx+flashrom@zenthought.org>
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r951 | snelson | 2010-03-19 23:35:21 +0100 (Fri, 19 Mar 2010) | 10 lines
+
+Rebased Board Enable Patch: Intel SE440BX-2
+
+This board has no subsystem IDs, but thankfully the DMI patch is in
+now, which is a real life safer. There are *WAY* to many 440BX/PIIX4
+boards out there to match this without DMI.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r950 | snelson | 2010-03-19 23:30:49 +0100 (Fri, 19 Mar 2010) | 11 lines
+
+Rebased Board Enable Patch: Abit VT6X4
+
+This board has *no* usable IDs at all, neither DMI nor PCI
+subsystem IDs. You have to force it using "-m abit:vt6x4"
+
+Try 3: really correct polarity of the GPIO
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r949 | snelson | 2010-03-19 23:26:44 +0100 (Fri, 19 Mar 2010) | 6 lines
+
+Rebased Board Enable Patch: Add Asus A8N.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r948 | snelson | 2010-03-19 19:47:06 +0100 (Fri, 19 Mar 2010) | 18 lines
+
+rename print_82802ab_status to print_status_82802ab
+add unlock_82802ab
+strip unlock code from erase_block_82802ab
+rename erase_82802ab_block  to erase_block_80280ab
+delete sharplhf00l04.o from Makefile
+delete *_lhf00l04* from chipdrivers.h
+add unlock_stm50flw0x0x
+delete wait_stm50flw0x0x
+delete write_page_stm50flw0x0x
+convert erase_stm50flw0x0x to erase_chip_stm50flw0x0x
+delete write_stm50flw0x0x
+add unlock_82802ab to two Intel chips with TEST_BAD_WRITE
+change the status of 82802AB, 82802AC, M50FW040, M50FW080 to TEST_OK_PR
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r947 | mkarcher | 2010-03-17 07:19:23 +0100 (Wed, 17 Mar 2010) | 7 lines
+
+Add board enable for P4C800-E
+
+lspci/flashrom/superiotool at
+http://www.coreboot.org/pipermail/flashrom/2010-March/002579.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r946 | hailfinger | 2010-03-17 01:47:56 +0100 (Wed, 17 Mar 2010) | 10 lines
+
+PCI device BARs of all types had only bits 1:0 cleared while reading the
+address. That was correct for IO BARs, but failed to mask bit 3:2 for
+MEM BARs, resulting in odd offsets for prefetchable MEM BARs and for
+64-bit capable MEM BARs.
+Mask the correct number of bits for all types of BARs and add some debug
+printing about BAR type.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r945 | uwe | 2010-03-17 01:05:59 +0100 (Wed, 17 Mar 2010) | 11 lines
+
+Mark a bunch of parallel chips I tested as TEST_OK_PRW.
+
+All operations for these chips were tested on hardware. ERASE is not marked
+as working yet, as there are multiple erase functions per chip and only one
+was (successfully) tested. I'll redo the ERASE test when the respective
+infrastructure in flashrom is there.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r944 | hailfinger | 2010-03-17 00:59:19 +0100 (Wed, 17 Mar 2010) | 6 lines
+
+Add MS-DOS crosscompilation support to flashrom. Tested, works fine.
+Part 1: Code changes.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r943 | snelson | 2010-03-16 04:09:10 +0100 (Tue, 16 Mar 2010) | 7 lines
+
+convert _sst_fwhub functions to jedec
+kill unused sst_fwhub.c functions
+make unlock_* check if unlock was successful and only return 0 when fully successful
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r942 | snelson | 2010-03-16 02:00:50 +0100 (Tue, 16 Mar 2010) | 6 lines
+
+remove function probe_28sf040
+delete references to dead sharplhf00l04.c and sst29sf040.c functions from chipdrivers.h
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r941 | snelson | 2010-03-16 01:51:31 +0100 (Tue, 16 Mar 2010) | 6 lines
+
+remove some copied functions (from 82802ab.c) and use the 82802ab equivalents
+fix missing prototypes to _82802ab functions
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r940 | snelson | 2010-03-16 01:45:00 +0100 (Tue, 16 Mar 2010) | 5 lines
+
+kill dead w39v080fa.c functions
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r939 | snelson | 2010-03-16 01:35:53 +0100 (Tue, 16 Mar 2010) | 5 lines
+
+kill dead w39v040c.c functions
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r938 | snelson | 2010-03-16 01:32:30 +0100 (Tue, 16 Mar 2010) | 5 lines
+
+kill dead pm49fl00x.c functions
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r937 | hailfinger | 2010-03-15 04:48:42 +0100 (Mon, 15 Mar 2010) | 16 lines
+
+Add FEATURE_REGISTERMAP to
+* Intel 82802AB, 82802AC
+* Sharp LHF00L04
+* SST SST49LF004C, SST49LF008C, SST49LF016C, SST49LF160C
+* ST M50FLW040A, M50FLW040B, M50FLW080A, M50FLW080B, M50FW002, M50FW016
+     M50FW040, M50FW080, M50LPW116
+
+Make register mapping conditional on FEATURE_REGISTERMAP in 82802ab.c.
+Replace probe_49lfxxxc with probe_82802ab.
+Replace probe_28sf040 with probe_82802ab.
+Replace probe_sst_fwhub with probe_jedec.
+Add printlock_sst_fwhub to chips which used probe_sst_fwhub.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r936 | mkarcher | 2010-03-14 18:57:52 +0100 (Sun, 14 Mar 2010) | 6 lines
+
+Skip DMI laptop check if DMI doesn't work
+
+Also further removes dead code from dmi.c and adds a missing newline.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r935 | mkarcher | 2010-03-14 01:00:14 +0100 (Sun, 14 Mar 2010) | 7 lines
+
+Enabling Gigabyte GA-MA69VM-S2
+
+This board has a supported chipset and a supported bios, but it's
+connected indirectly through IT8716 and not recognized.
+
+Signed-off-by: Ra?\195?\186l Soriano <GatoLoko@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r934 | mkarcher | 2010-03-14 00:47:09 +0100 (Sun, 14 Mar 2010) | 8 lines
+
+Fix EN29F002 Top/Bottom Boot Block
+
+See http://www.coreboot.org/pipermail/flashrom/2010-March/002480.html
+for effects of mixup: blockwise erase will fail, fallback to chip
+erase works.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r933 | uwe | 2010-03-13 18:28:29 +0100 (Sat, 13 Mar 2010) | 12 lines
+
+Various coding style and cosmetic changes (trivial).
+
+ - Fix coding-style, whitespace, and indentation in a few places.
+
+ - Consistently use the same spelling ("Super I/O") everywhere.
+
+ - Make some flashrom stdout output look a bit nicer.
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r932 | mkarcher | 2010-03-13 15:47:48 +0100 (Sat, 13 Mar 2010) | 7 lines
+
+Patch: Manpage: Move description of layout file into the right place
+
+Move the description of the layout file out of the --chip option
+into the --layout option.
+
+Signed-off-by: Joerg Mayer <jmayer@loplof.de>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r931 | mkarcher | 2010-03-12 07:41:39 +0100 (Fri, 12 Mar 2010) | 4 lines
+
+Tell users to probe/backup first
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r930 | mkarcher | 2010-03-12 00:04:16 +0100 (Fri, 12 Mar 2010) | 6 lines
+
+Fix NULL pointer reference in board_flash_enable.
+
+Was introduced in r926. Found by Henrik Kretzschmar <henne@nachtwindheim.de>.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+------------------------------------------------------------------------
+r929 | mkarcher | 2010-03-09 17:57:06 +0100 (Tue, 09 Mar 2010) | 7 lines
+
+Add ASUS A7V8X-X write-enable.
+
+I have an ASUS A7V8X-X, the BIOS programming requires a write-enable. It
+has an IT8712F, just like the A7V600-X.
+
+Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r928 | mkarcher | 2010-03-09 17:53:06 +0100 (Tue, 09 Mar 2010) | 6 lines
+
+Mark PMC Pm49FL002 as tested.
+
+This chip is on my ASUS A7V8X-X mainboard.
+
+Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r927 | hailfinger | 2010-03-08 01:42:32 +0100 (Mon, 08 Mar 2010) | 21 lines
+
+Write granularity is chip specific. The following write
+granularities exist according to my datasheet survey:
+- 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.
+- 256 bytes. If less than 256 bytes are written, the contents of the
+  unwritten bytes are undefined.
+
+Note that chips with default 256-byte writes, which keep the
+original contents for unwritten bytes, have a granularity of 1 byte.
+
+Handle 1-bit, 1-byte and 256-byte write granularity.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r926 | mkarcher | 2010-03-07 23:29:28 +0100 (Sun, 07 Mar 2010) | 7 lines
+
+Move untested board enable documentation to manpage
+
+This also checks the testedness of boards in all cases, not just for
+PCI/DMI detection.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r925 | mkarcher | 2010-03-07 17:52:59 +0100 (Sun, 07 Mar 2010) | 6 lines
+
+Board enable for MS-7202 (K8N GM2-L)
+
+Board enable code is untested, marked as such.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r924 | mkarcher | 2010-03-07 17:42:55 +0100 (Sun, 07 Mar 2010) | 6 lines
+
+Board enable for Asus M2NBP-VM CSM
+
+Board info: http://www.coreboot.org/pipermail/flashrom/2009-December/001373.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r923 | mkarcher | 2010-03-07 17:32:32 +0100 (Sun, 07 Mar 2010) | 10 lines
+
+Board enable for HP Vectra VL420SFF
+
+This code has been tested by Mattias Mattsson on 23. December 2009,
+but without the DMI match. Now that DMI support is in and working,
+the board can be added to mainline flashrom.
+
+board info: http://www.coreboot.org/pipermail/flashrom/2009-December/001440.html
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r922 | mkarcher | 2010-03-07 13:11:08 +0100 (Sun, 07 Mar 2010) | 16 lines
+
+Refactor man page
+
+This patch puts the description of the different programmers into a
+separate section of the manpage instead of having them one after the
+other without visual structuring in the description of "-p". It is
+made as a preparation of a man-page patch that adds the background
+of board enables into flashrom.8 that would really blow up the OPTIONS
+section.
+
+The only differences in content are:
+ - The parameter for serprog is mandatory, not optional
+ - Default behaviour of it87spi (using BIOS-set I/O address) is mentioned.
+ - Default speed of buspiratespi is mentioned.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r921 | snelson | 2010-03-05 09:44:11 +0100 (Fri, 05 Mar 2010) | 9 lines
+
+Add support for Eon EN29F010.
+Tested by Russ Dill.
+Checked against datasheet by Sean Nelson.
+Datasheet: http://www.essi.com.tw/upfile/p2008929171446.pdf
+
+Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r920 | mkarcher | 2010-03-03 17:15:12 +0100 (Wed, 03 Mar 2010) | 6 lines
+
+Board enable for Abit IP35 Pro
+
+This board is like the IP35. Just changed the IDs to match.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Timothy Lepre <Klavious@gmail.com>
+------------------------------------------------------------------------
+r919 | mkarcher | 2010-02-28 02:33:48 +0100 (Sun, 28 Feb 2010) | 12 lines
+
+Implement tested/untested status for board enables
+
+The message printing code greatly exceed the 80 character limit. I can
+reformat it on request to obey the limit.
+
+Intended behaviour:
+on untested boards an explanation of that status is printed and the board
+enable code is not run, unless the option "boardenable=force" has been
+passed to the internal programmer.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r918 | mkarcher | 2010-02-27 19:35:54 +0100 (Sat, 27 Feb 2010) | 7 lines
+
+Board enable for HP Vectra VL400
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: bas nowaira <bas429@gmail.com>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r917 | snelson | 2010-02-27 19:01:15 +0100 (Sat, 27 Feb 2010) | 9 lines
+
+Since we have a unlock interface for chips, I think we can convert the remaining references to *_49fl00x. Now the only remaining and used function in pm49fl00x.c is unlock_49fl00x.
+
+Added missing unlock to AMIC A49LF040A.
+Added lock_49fl00x function; Trivial change.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r916 | mkarcher | 2010-02-26 10:51:20 +0100 (Fri, 26 Feb 2010) | 4 lines
+
+Warn if running on laptops
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r915 | mkarcher | 2010-02-26 10:51:16 +0100 (Fri, 26 Feb 2010) | 4 lines
+
+Factor out DMI string reading into subfunction
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r914 | snelson | 2010-02-26 06:48:29 +0100 (Fri, 26 Feb 2010) | 17 lines
+
+Split spi.c into programmer and chip code
+Remove chipdriver.h include from flash.h
+Some of the spi programmer drivers required chipdrivers.h, needs fixing later:
+  it87spi.c
+  ichspi.c
+  sb600spi.c
+  wbsio_spi.c
+  buspirate_spi.c
+  ft2232spi.c
+  bitbang_spi.c
+  dediprog.c
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+
+------------------------------------------------------------------------
+r913 | mkarcher | 2010-02-25 12:38:23 +0100 (Thu, 25 Feb 2010) | 9 lines
+
+Rename identifiers called 'byte'
+
+Still fallout of adding "-Wshadow". Missed the ht1000 one
+(chipset_enable is not compied on Windows where we had the collision
+with "byte" last time) and the other occurrence is newly introduced.
+Old libpci defines a global symbol called "byte" too.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r912 | mkarcher | 2010-02-24 23:43:44 +0100 (Wed, 24 Feb 2010) | 7 lines
+
+Remove unused short IDs
+
+This also replaces the meaningless numbers in the DMI debug printout
+with the parameter names.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r911 | mkarcher | 2010-02-24 01:04:40 +0100 (Wed, 24 Feb 2010) | 7 lines
+
+Replace PCI_OK/PCI_NT by OK/NT
+
+We don't need to duplicate OK and NT as PCI_OK and PCI_NT if the symbols
+are already there (defined for the chipset enable table).
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r910 | mkarcher | 2010-02-24 01:00:21 +0100 (Wed, 24 Feb 2010) | 7 lines
+
+Fix PIIX4 GPO set
+
+Intel datasheet says "byte accesses only". Looks like they mean it.
+Also fix use of or instead of and for lowering GPOs.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+------------------------------------------------------------------------
+r909 | snelson | 2010-02-22 16:52:57 +0100 (Mon, 22 Feb 2010) | 14 lines
+
+patch to remove all references to dead chipdrivers.
+We also need to 'svn rm' the following files:
+  am29f040b.c
+  en29f002a.c
+  m29f002.c
+  mx29f002.c
+  pm29f002.c
+  sst49lf040.c
+  w49f002u.c
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r908 | uwe | 2010-02-21 22:17:00 +0100 (Sun, 21 Feb 2010) | 9 lines
+
+Add initial (non-working) code for Highpoint ATA/RAID controllers.
+
+It's disabled by default. The current status is detailed at:
+http://www.flashrom.org/pipermail/flashrom/2010-January/001828.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r907 | snelson | 2010-02-19 01:52:10 +0100 (Fri, 19 Feb 2010) | 22 lines
+
+Here's a very quick patch to fix the missing unlock code.
+Fixes missing unlock for certain chips:
+ * unlock_49lf00x
+    * Pm49fl002
+    * Pm49fl004
+
+ * unlock_49flxxxc
+    * SST49LF160C
+
+ * unlock_winbond_fwhub
+    * W39V080FA
+    * W39V080FA (dual mode)
+
+Fixes missing printlock for certain chip:
+ * printlock_w39v040c
+    * W39V040C
+
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+
+------------------------------------------------------------------------
+r906 | hailfinger | 2010-02-18 13:24:38 +0100 (Thu, 18 Feb 2010) | 9 lines
+
+Refactor MCP SPI detection:
+- Set supported buses based on ISA bridge reg 0x8a
+- Use MCP55 chipset enable only if LPC is detected
+- Allow LPC on MCP61
+- Eliminate duplicated code where possible
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r905 | mkarcher | 2010-02-16 01:49:50 +0100 (Tue, 16 Feb 2010) | 10 lines
+
+more NetBSD fixes (w/ patch)
+
+Cast input to tolower() to unsigned char to work around how tolower() is
+implemented on NetBSD.
+
+Also, use CPPFLAGS (rather than overriding CFLAGS) for the
+NetBSD/DragonFly build example.
+
+Signed-off-by: Jonathan A. Kollasch <jakllsch@kollasch.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r904 | hailfinger | 2010-02-14 02:20:28 +0100 (Sun, 14 Feb 2010) | 28 lines
+
+Some programmers want to run certain functions during programmer
+shutdown, but the function choice depends on the code path taken during
+programmer init.
+Rather than rebuilding the whole init logic in the shutdown function, it
+is now possible to register functions for execution on programmer
+shutdown.
+The behaviour is similar to atexit(), but the registered functions will
+be run on programmer shutdown instead of on exit and the functions will
+be called with a void * argument that is specified on registration.
+Registered functions must have the prototype
+void function(void *);
+and will be executed in reverse registration order directly before
+calling the programmer-specific shutdown() function. It is recommended
+to have shutdown() only disable programmer/hardware access and leave all
+code path sensitive shutdown to functions registered with
+register_shutdown().
+
+The most prominent use case is resetting the EC after flashing on
+laptops.
+
+Note: There are quite a few code paths in flashrom which proceed to
+terminate flashrom without any programmer shutdown. Those code paths
+will not get the benefit of register_shutdown() and they should be
+changed wherever possible.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r903 | hailfinger | 2010-02-14 02:00:36 +0100 (Sun, 14 Feb 2010) | 6 lines
+
+Use uname -p instead of -m on NetBSD so we get the right
+architecture library name.
+
+Signed-off-by: Jonathan A. Kollasch <jakllsch@kollasch.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r902 | hailfinger | 2010-02-14 00:41:01 +0100 (Sun, 14 Feb 2010) | 29 lines
+
+Add SPI mode diagnostics for all post-MCP55 (nForce 5) chipsets from
+Nvidia.
+
+Huge thanks to Michael Karcher for reverse engineering the MCP67 chipset
+and writing a spec. Due to this, we were able to use the chinese wall
+technique for 100% clean room reverse engineering.
+
+This patch doesn't touch any of the new registers, it only reads them.
+Assuming that read has no side effects, this patch is a no-op and safe.
+
+We need "flashrom -V" output from all post-MCP55 (nForce 5) chipset
+boards. Please indicate if your board uses SPI flash or LPC flash (if
+you know it). Note: That output is only helpful if it is created with
+patched flashrom and if is from the first run of flashrom after a cold
+boot (reset or Ctrl-Alt-Del is not sufficient). There is a pattern based
+on which we can probably detect which flash type is present on the
+board.
+
+Thanks to Alessandro Polverini for testing earlier iterations of this
+patch.
+
+Note: The MCP67 should work. I guessed that the other recent Nvidia
+chipsets would work in a similar way, and created a simplified
+do-nothing catchall chipset enable function which dumps some info and
+instructs the user to send more info.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r901 | hailfinger | 2010-02-13 20:22:11 +0100 (Sat, 13 Feb 2010) | 5 lines
+
+Kill an erroneous .erase introduced in r900.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r900 | snelson | 2010-02-13 19:41:53 +0100 (Sat, 13 Feb 2010) | 5 lines
+
+Adds support for the Intel E28F004S5 flash chip.
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r899 | hailfinger | 2010-02-12 20:37:25 +0100 (Fri, 12 Feb 2010) | 14 lines
+
+SPI RES is the most unreliable way to identify chips because it only
+returns a 1-byte ID for most chips. For every given ID out there,
+probably a dozen incompatible flash chips match it.
+We already refuse to identify a chip with RES if that chip responds to
+RDID (3 bytes, good match), and with this patch we additionally refuse
+RES if the chip responds to REMS (2 bytes, still a good match). This
+increases matching accuracy a lot.
+
+Besides that, the RDID/REMS response checking has been cleaned up for
+better readability.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r898 | hailfinger | 2010-02-12 20:35:25 +0100 (Fri, 12 Feb 2010) | 11 lines
+
+Linking in support for the internal programmer doesn't make sense if you
+only need hardware (ioport, memory) access.
+Split internal.c into internal.c and hwaccess.c.
+
+Note: This patch was created by "svn cp internal.c hwaccess.c" and then
+removing stuff from both files. That's why you can't apply the patch
+as-is before running the svn cp.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r897 | snelson | 2010-02-12 19:40:27 +0100 (Fri, 12 Feb 2010) | 6 lines
+
+Fix erase blocks for Winbond W25X{10,20,40,80} SPI chips. The Winbond W25X10 and related chips only have 4k and 64k blocks and only accept erase commands: 20h, d8h, and c7h.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+
+------------------------------------------------------------------------
+r896 | mkarcher | 2010-02-12 06:44:18 +0100 (Fri, 12 Feb 2010) | 6 lines
+
+Fix DMI match logic
+
+This bug slipped in on changing back match-specific to match-any
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r895 | hailfinger | 2010-02-12 00:03:53 +0100 (Fri, 12 Feb 2010) | 12 lines
+
+At long last, the day has come, and we can bury full-chip erase once and
+for all.  Back in November 2008(!) I proposed the first version of the
+flexible sector-based erase structure, and now we can finally rip out
+the old full-chip erase code without ill effects.
+Rejoice and party!
+
+Thanks to everyone who made this possible, especially to Sean Nelson who
+converted the majority of flash chips to sector erase.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r894 | hailfinger | 2010-02-11 12:28:37 +0100 (Thu, 11 Feb 2010) | 31 lines
+
+This megapatch rewrites substantial parts of ICH SPI to actually do what
+the SPI layer wants instead of its own weird idea about commands
+(running unrequested commands, running modified commands).
+Besides that, there is a fair share of cleanups as well.
+
+- Add JEDEC_EWSR (Enable Write Status Register) to default commands.
+- Mark a no longer used opcode/preopcode table as unused.
+- Declare all commands as non-atomic/standalone by default. The ICH SPI
+driver has no business executing commands (preopcodes) automatically if
+they were not requested.
+- Automatically adjust preopcode/opcode pairings (like WREN+ERASE) based
+on what the SPI layer requested. The ICH SPI driver has no business
+executing altered opcode pairs as it sees fit.
+- Fix incomplete initialization in the case of a locked down chipset.
+Leaving the first 4 opcodes with uninitialized pairings had
+unpredictable results.
+- switch() exists for a reason. Nested if() checking on the same
+variable is an interesting style.
+- Actually check if the requested readcnt/writecnt for a command is
+supported by the hardware instead of delivering corrupt/incomplete
+commands and data.
+- If a command has unsupported readlen/writelen, complain loudly to the
+user.
+- Use find_opcode instead of open-coding the same stuff in a dozen
+variations.
+- Introduce infrastructure for updating the command set of unlocked
+chipsets on the fly.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: David Hendricks <dhendrix@google.com>
+
+------------------------------------------------------------------------
+r893 | hailfinger | 2010-02-04 12:12:04 +0100 (Thu, 04 Feb 2010) | 8 lines
+
+Document the rules for DMI matching with PCI subsystem IDs.
+
+The rules may change in the future, but right now it is important that
+the comments match the code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r892 | mkarcher | 2010-02-04 11:58:50 +0100 (Thu, 04 Feb 2010) | 6 lines
+
+Allow DMI supported board enables with subsystem ID zero.
+
+This is needed for the Intel SE440BX-2 as well as the Asus P5A.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r891 | oxygene | 2010-02-04 09:29:18 +0100 (Thu, 04 Feb 2010) | 7 lines
+
+Properly initialize USB device in dediprog driver.
+That's necessary to use bulk transfers, and just the
+right thing in any case.
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r890 | uwe | 2010-02-04 03:40:16 +0100 (Thu, 04 Feb 2010) | 8 lines
+
+Add a second set of PCI IDs for the Tekram P6Pro-A5 (trivial).
+
+(Re-)tested on hardware, detection works OK.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r889 | hailfinger | 2010-02-02 12:09:03 +0100 (Tue, 02 Feb 2010) | 20 lines
+
+Create a physical memory mapping function which requests cached readonly
+memory. This should take care of picky Linux kernels which do not allow
+uncached mappings to cached areas.
+Handle mapping failure gracefully (no forced exit()) if the caller
+specifies it.
+
+Such cached areas which can handle mapping failure are DMI tables and
+coreboot tables. On failure we just ignore those tables. That is not
+perfect, but a lot better than aborting flashrom due to an error in
+nonessential functionality.
+
+This should fix flashrom on a sizable number of machines where it
+currently aborts early.
+
+Yes, I could have exploited a Linux kernel bug to "solve" this, but
+relying on such bugs is not exactly the best idea.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Vincent Pelletier <plr.vincent@gmail.com>
+
+------------------------------------------------------------------------
+r888 | snelson | 2010-02-01 06:49:46 +0100 (Mon, 01 Feb 2010) | 6 lines
+
+Adds support for ST M29W512B. Tested and works for me.
+
+Signed-off-by: Jeffrey A. Kent <jakent@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r887 | uwe | 2010-01-31 21:13:06 +0100 (Sun, 31 Jan 2010) | 12 lines
+
+Add the Tekram P6Pro-A5 board as supported (trivial).
+
+The board doesn't need a board-enable, writing works out of the box.
+
+Also, the board can only decode 256KB. I verified this by writing a 512KB
+image of random bytes (which fails), whereas 256KB of random bytes can be
+written correctly.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r886 | snelson | 2010-01-29 00:55:12 +0100 (Fri, 29 Jan 2010) | 32 lines
+
+Complete the addition of Feature Bits for all Jedec based chips.
+Add FEATURE_SHORT_RESET, FEATURE_LONG_RESET, and FEATURE_EITHER_RESET
+rewrite jedec functions to use getaddrmask
+
+convert write_49f002 to write_jedec_1
+convert write_w39v040c to write_jedec_1
+convert probe_w39v040c to probe_jedec
+convert write_49lf040 to write_jedec_1
+convert write_pm29f002 to write_jedec
+convert write_29f040b to write_jedec_1
+convert probe_29f040b to probe_jedec
+convert erase_chip_29f040b to erase_chip_block_jedec
+convert erase_sector_29f040b to erase_sector_jedec
+convert write_m29f002b to write_jedec
+convert write_m29f002t to write_jedec
+convert *_29f002 to *_jedec
+
+decouple unused files from Makefile:
+am29f040b.c
+en29f002a.c
+m29f002.c
+mx29f002.c
+pm29f002.c
+sst49lf040.c
+w39v040c.c
+w49f002u.c
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Anders Juel Jensen <andersjjensen@gmail.com>
+
+
+------------------------------------------------------------------------
+r885 | uwe | 2010-01-28 20:02:36 +0100 (Thu, 28 Jan 2010) | 16 lines
+
+The GIGABYTE GA-7ZM has a maximum decode size (parallel chips) of 512 KB.
+
+Add this information to the new field in the board-enable table. We match the
+board via two sets of PCI IDs. However, as we don't need a board-enable
+function for this board (it works out of the box; well, at least if you remove
+the JP9 jumper on the board), change the code to allow NULL as value for
+the board-enable function. There will likely be more boards in the future where
+we want to record a maximum decode size but which don't need a board-enable.
+
+This is hardware-tested on the GIGABYTE GA-7ZM by successfully writing a 512KB
+image of random bytes to a chip in this board.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r884 | mkarcher | 2010-01-27 11:08:33 +0100 (Wed, 27 Jan 2010) | 9 lines
+
+Avoid bogus gcc warning
+
+recent gcc/glibc combinations warn about ignoring the fgets() result.
+The problem exists on Ubuntu 9.10 with current updates. This "fix" of
+the non-problem (as I check ferror() afterwards) should even be a
+(negligible) performance optimization.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Andrew Morgan <ziltro@ziltro.com>
+------------------------------------------------------------------------
+r883 | oxygene | 2010-01-26 21:58:40 +0100 (Tue, 26 Jan 2010) | 9 lines
+
+Windows wants UNC names for COM ports >9 (legacy COM ports only work with one digit).
+As UNC also works for smaller names, just retarget all requests for dev=COMx on win32
+to \\.\COMx.
+Tested with large and small COM port numbers on XP.
+
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r882 | oxygene | 2010-01-25 23:55:33 +0100 (Mon, 25 Jan 2010) | 6 lines
+
+Open binary files in binary mode. No change on UNIX (or Mac OS,
+according to its documentation), but fixes operation on Windows.
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r881 | uwe | 2010-01-23 16:15:19 +0100 (Sat, 23 Jan 2010) | 8 lines
+
+Add support for the SST39SF512 chip.
+
+All operations tested by me, works fine.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r880 | stepan | 2010-01-22 11:49:33 +0100 (Fri, 22 Jan 2010) | 6 lines
+
+backout unintentional chunk.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r879 | hailfinger | 2010-01-22 03:53:30 +0100 (Fri, 22 Jan 2010) | 8 lines
+
+Add write support.
+Speed up reads by a factor of 4 by switching block size from 4 to 16.
+Add support for 4 byte RDID.
+Add USB error decoding via usb_strerror.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r878 | stepan | 2010-01-21 21:26:30 +0100 (Thu, 21 Jan 2010) | 6 lines
+
+This patch fixes the use of CFLAGS and CPPFLAGS in the flashrom makefile
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com> 
+
+
+------------------------------------------------------------------------
+r877 | snelson | 2010-01-20 21:55:53 +0100 (Wed, 20 Jan 2010) | 41 lines
+
+Convert the following chips to block_erasers: 
+SST28SF040A 
+SST29EE010 
+SST29LE010 
+SST29EE020A 
+SST29LE020 
+SST39SF010A 
+SST39SF020A 
+SST39SF040 
+SST39VF512 
+SST39VF010 
+SST39VF020 
+SST39VF040 
+SST39VF080 
+SST49LF002A/B 
+SST49LF003A/B 
+SST49LF004C 
+SST49LF008A 
+SST49LF008C 
+SST49LF016C 
+SST49LF020 
+SST49LF020A 
+SST49LF040 
+SST49LF040B 
+SST49LF080A 
+SST49LF160C 
+
+Extend sst28sf040 to include chip and sector functions for block_eraser.
+Extend sst49lfxxxc to include chip, sector, block erasers functions for block_erasers.
+Extend sst_fwhub to include chip and sector functions for block_erasers.
+Add copyrights to changed files.
+Killed erase_sst_fwhub.
+Killed erase_49lfxxxc.
+NULL A/A mux mode full chip erasers.
+Ignore block locks in erase/write.
+Change comments from "PP mode" to "A/A mux mode"
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com> 
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+
+------------------------------------------------------------------------
+r876 | libv | 2010-01-20 15:45:07 +0100 (Wed, 20 Jan 2010) | 6 lines
+
+Boards: Remove it8705_rom_write_enable.
+
+Should be functionally the same as it8705f_write_enable_2e.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+------------------------------------------------------------------------
+r875 | libv | 2010-01-20 15:45:03 +0100 (Wed, 20 Jan 2010) | 6 lines
+
+Boards: Add max_rom_decode_parallel entry to board enable table.
+
+This is a quick fix for board specific parallel addressing limits.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r874 | mkarcher | 2010-01-20 15:14:11 +0100 (Wed, 20 Jan 2010) | 33 lines
+
+Matching board via DMI
+
+If a board is not uniquely identifiable by PCI device/subsystem IDs, a
+string can be specified to be looked for (case-sensitive, substring or
+anchored) for now in one of the following DMI items in addition to matching
+the PCI IDs:
+ - System Manufacturer
+ - System Product Name
+ - System Version
+ - Baseboard Manufacturer
+ - Baseboard Product Name
+ - Baseboard Version
+
+Strings are anchored re-like (^ at the beginning, $ at the end), but
+there are no plans to support full regular expressions and matched to any
+of the mentioned fields.
+
+The match is only made if DMI info is available and the string matches.
+If no DMI info is available and the PCI IDs match, a warning is printed
+as the board can not be autodetected.
+
+It's still open to discussion whether we add an DMI override switch to
+specify a string that will definitely match, and whether this switch is
+only used if no DMI is available or whether it overrides or augments DMI
+data.
+
+DMI data is currently read using dmidecode. This tool is available for
+all major platforms except MacOS X. I heard that there also is a MacOS X
+version of dmidecode, but didn't investigate that.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r873 | snelson | 2010-01-19 21:23:26 +0100 (Tue, 19 Jan 2010) | 5 lines
+
+Fix SyncMOS S29C51004T, which has 512 uniform 1k sectors.
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+
+------------------------------------------------------------------------
+r872 | snelson | 2010-01-19 17:39:19 +0100 (Tue, 19 Jan 2010) | 41 lines
+
+Convert ST to block erasers:
+ST M25P05-A
+ST M25P05.RES
+ST M25P10-A
+ST M25P10.RES
+ST M25P20
+ST M25P40
+ST M25P40-old
+ST M25P80
+ST M25P16
+ST M25P32
+ST M25P64
+ST M25P128
+ST M29F002B
+ST M29F002T/NT
+ST M29F040B
+ST M29F400BT
+ST M29W010B
+ST M29W040B
+ST M50FLW040A
+ST M50FLW040B
+ST M50FLW080A
+ST M50FLW080B
+ST M50FW002
+ST M50FW016
+ST M50FW040
+ST M50FW080
+ST M50LPW116
+
+Add erase_chip_stm50flw0x0x to stm50flw0x0x.c
+Add copyright to stm50flw0x0x.c
+Fix block sizes and counts
+Omit M50FLW0x0x mixed sector/block eraser
+Convert the used 82802ab functions to their stm50flw0x0x equivalents
+Fix incorrect sizes as found by Carl-Daniel.
+Add back M50FLW0x0x mixed sector/block eraser sans function pointer.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r871 | snelson | 2010-01-19 17:08:51 +0100 (Tue, 19 Jan 2010) | 15 lines
+
+Convert chips to block_erasers:
+
+SyncMOS S29C31004T
+SyncMOS S29C51001T
+SyncMOS S29C51002T
+SyncMOS S29C51004T
+TI TMS29F002RT
+TI TMS29F002RB
+
+SyncMOS chips have Uniform sector; boot blocks on chips are made up of uniform sectors but have locking.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r870 | hailfinger | 2010-01-19 12:15:48 +0100 (Tue, 19 Jan 2010) | 21 lines
+
+Dediprog SF100 support.
+
+Reverse engineered from USB logs. I never touched that programmer nor
+did I ever see the associated software.
+Disabled by default until it is complete. The driver needs to be hooked
+up to the SPI core before it will do anything besides init and
+diagnostics.
+
+I successfully reverse engineered all commands, but some are still
+somewhat magic.
+Logs from "flashrom -p dediprog -V" are appreciated.
+
+Probe and read should work, erase/write is expected to explode.
+The programmer will set voltage to 0 on exit.
+
+Thanks a lot to Stefan Reinauer and Patrick Georgi for providing USB
+logs and for testing the result.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r869 | hailfinger | 2010-01-19 07:42:46 +0100 (Tue, 19 Jan 2010) | 8 lines
+
+Add eraseblock functions to self-check. It doesn't make sense to have
+different layouts for the same function on one chip.
+Keep going if an error is found, we want all errors to be reported in
+one fell swoop.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r868 | snelson | 2010-01-19 04:24:55 +0100 (Tue, 19 Jan 2010) | 27 lines
+
+Converted chips to block_erasers:
+W_25X10
+W_25X20
+W_25X40
+W_25X80
+W_25X16
+W_25X32
+W_25X64
+W_29C011
+W_29C020C
+W_29C040P
+W_29EE011
+W_39V040A
+W_39V040B
+W_39V040C
+W_39V040FA
+W_39V080A
+W_49F002U
+W_49V002A
+W_49V002FA
+W_39V080FA
+W_39V080FA_DM
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r867 | snelson | 2010-01-19 04:23:07 +0100 (Tue, 19 Jan 2010) | 24 lines
+
+Convert chips to block_erasers:
+ST_M25PE10
+ST_M25PE20
+ST_M25PE40
+ST_M25PE80
+ST_M25PE16
+PMC_25LV010
+PMC_25LV016B
+PMC_25LV020
+PMC_25LV040
+PMC_25LV080B
+PMC_25LV512
+PMC_39F010
+PMC_49FL002
+PMC_49FL004
+SANYO_LE25FW203A
+SPANSION_S25FL016A
+
+Added spi_block_erase_d7 for PMC chips.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r866 | hailfinger | 2010-01-19 03:19:27 +0100 (Tue, 19 Jan 2010) | 10 lines
+
+Add Intel NM10 chipset enable.
+Public chipset documentation available at
+http://www.intel.com/Assets/PDF/datasheet/322896.pdf
+
+Tested on NM10-based customer reference board from Intel.
+
+Signed-off-by: David Hendricks <dhendrix@google.com>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r865 | snelson | 2010-01-18 09:24:02 +0100 (Mon, 18 Jan 2010) | 6 lines
+
+Fix A25L40PU and A2540PT due to incorrect full-chip block size is incorrect.
+Thanks to hailfinger's self-check-erase routine for catching this.
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r864 | hailfinger | 2010-01-18 09:14:43 +0100 (Mon, 18 Jan 2010) | 10 lines
+
+Flashrom performs a self-check on every startup before it even starts to
+initialize any programmer. That way, compiler errors and code errors
+will be caught before they can do any harm.
+This patch adds an eraseblock structure self-check.
+It also modifies the self-check code to consistently run all checks even
+if one check failed.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r863 | hailfinger | 2010-01-18 08:02:19 +0100 (Mon, 18 Jan 2010) | 6 lines
+
+The write and erase column in the --list-supported-wiki output were
+swapped. Thanks to Michael Karcher for noticing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r862 | mkarcher | 2010-01-13 00:29:30 +0100 (Wed, 13 Jan 2010) | 7 lines
+
+Support for Spansion S25FL008A
+
+Tested with read/erase/write (including verify). I only wrote the image
+that was read before - don't want to brick my laptop.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r861 | mkarcher | 2010-01-13 00:29:26 +0100 (Wed, 13 Jan 2010) | 7 lines
+
+Don't use "byte" as identifier.
+
+Some mingw declares a global identifier "byte", causing -Werror -Wshadow
+to break compilation. This patch renames all identifiers called "byte".
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r860 | mkarcher | 2010-01-12 16:36:24 +0100 (Tue, 12 Jan 2010) | 11 lines
+
+Enable -Wshadow, clean code for that
+
+This is not just for fun. We hit a real bug on BSD with the outl macros.
+The macro variable tmp collided with the tmp from outer scope.
+
+second revision, now also taking care of inb/inw/inl. While that shadowing
+did not introduce bugs (yet), of course it breaks the build on BSD when
+-Wshadow is enabled.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+------------------------------------------------------------------------
+r859 | libv | 2010-01-10 16:01:08 +0100 (Sun, 10 Jan 2010) | 8 lines
+
+Chipset: Fix sis5x0 register write verification.
+
+Also remove separate sis 5596 routine: superio code will be handled
+separately, which then turns this routine into the sis 5511 chipset
+enable.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r858 | hailfinger | 2010-01-10 14:28:48 +0100 (Sun, 10 Jan 2010) | 11 lines
+
+If neither internal (old default) nor dummy (safe default) programmer
+are selected, we must pick a sensible default programmer. Since there is
+no reason to prefer a particular external programmer, we abort
+compilation 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.
+This fixes single-programmer compilation.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r857 | hailfinger | 2010-01-10 02:59:50 +0100 (Sun, 10 Jan 2010) | 5 lines
+
+Convert all messages in sb600spi.c to the new message infrastructure.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r856 | hailfinger | 2010-01-10 02:34:00 +0100 (Sun, 10 Jan 2010) | 7 lines
+
+Change a few probe timings to TIMING_FIXME. They previously had
+TIMING_IGNORED, but now they use probe_jedec directly or indirectly and
+that function does not ignore probe timing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r855 | snelson | 2010-01-10 02:09:58 +0100 (Sun, 10 Jan 2010) | 7 lines
+
+Convert all messages in it87spi.c to the new message infrastructure.
+Change one msg_pdbg to msg_pinfo, change 7 msg_pinfo to msg_pdbg.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r854 | snelson | 2010-01-10 02:08:37 +0100 (Sun, 10 Jan 2010) | 7 lines
+
+Convert all messages in ft2232_spi.c to the new message infrastructure. 
+Fix one pinfo message to be pdbg.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r853 | snelson | 2010-01-10 02:06:23 +0100 (Sun, 10 Jan 2010) | 7 lines
+
+Convert all messages in serprog.c to the new message infrastructure.
+Rename some msg_pdbg to msg_pspew.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r852 | snelson | 2010-01-10 00:58:37 +0100 (Sun, 10 Jan 2010) | 6 lines
+
+Convert all messages in bitbang_spi.c to the new message infrastructure.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r851 | snelson | 2010-01-10 00:56:41 +0100 (Sun, 10 Jan 2010) | 6 lines
+
+Convert all messages in buspirate_spi.c to the new message infrastructure.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r850 | snelson | 2010-01-10 00:54:05 +0100 (Sun, 10 Jan 2010) | 5 lines
+
+Convert all messages in gfxnvidia.c to the new message infrastructure.
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r849 | snelson | 2010-01-10 00:50:27 +0100 (Sun, 10 Jan 2010) | 6 lines
+
+Convert all messages in satasii.c to the new message infrastructure.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r848 | snelson | 2010-01-10 00:46:39 +0100 (Sun, 10 Jan 2010) | 4 lines
+
+Convert all messages in serial.c to the new message infrastructure.
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r847 | snelson | 2010-01-10 00:34:45 +0100 (Sun, 10 Jan 2010) | 6 lines
+
+Convert all messages in wbsio_spi.c to the new message infrastructure.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r846 | mkarcher | 2010-01-10 00:31:13 +0100 (Sun, 10 Jan 2010) | 10 lines
+
+commit 845 is wrong, as I deleted a wrong line when I wanted to remove
+debugging print code. This (hopefully obviously correct) patch fixes the
+issue. As a previous version (before adding the debugging statement) was
+already executed on the board, the missing OUTW was executed on the
+testers machine on an earlier flashrom run.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+
+------------------------------------------------------------------------
+r845 | mkarcher | 2010-01-09 18:36:06 +0100 (Sat, 09 Jan 2010) | 6 lines
+
+Enable flashing on MSI 651M-L.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sergey Lichack <shadowpilot34@gmail.com>
+
+
+------------------------------------------------------------------------
+r844 | hailfinger | 2010-01-09 15:18:01 +0100 (Sat, 09 Jan 2010) | 7 lines
+
+Fix Makefile dependencies if FT2232SPI is not selected.
+.features was always regenerated in that case, triggering whole-project
+recompiles even if nothing changed.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r843 | snelson | 2010-01-09 06:30:14 +0100 (Sat, 09 Jan 2010) | 49 lines
+
+Convert chips to block_erasers:
+ASD AE49F2008
+AMIC A25L40P(T/U)
+AMIC A49LF040A
+EMST F49B002UA
+Eon EN25B05
+Eon EN25B10
+Eon EN25B20
+Eon EN25B40
+Eon EN25B80
+Eon EN25B16
+Eon EN25B32
+Eon EN25B64
+Eon EN25D16
+Eon EN25F05
+Eon EN25F10
+Eon EN25F20
+Eon EN25F40
+Eon EN25F80
+Eon EN25F16
+Eon EN25F32
+Intel 28F001BX-B
+Intel 28F001BX-T
+Intel 82802AB
+Intel 82802AC
+Macronix MX25L1635D
+Macronix MX25L3235D
+Macronix MX25L6405
+Macronix MX25L12805
+Macronix MX29F001B
+Macronix MX29F001T
+Macronix MX29LV040
+
+Added new chips (according to datasheets):
+Eon EN25B05T
+Eon EN25B10T
+Eon EN25B20T
+Eon EN25B40T
+Eon EN25B80T
+Eon EN25B16T
+Eon EN25B32T
+Eon EN25B64T
+
+Added minor Device IDs for Eon EN25Bxx{T,B} chips.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r842 | hailfinger | 2010-01-09 05:32:23 +0100 (Sat, 09 Jan 2010) | 12 lines
+
+Convert dummyflasher to msg_* and make good use of msg_pspew.
+Rule of thumb: Diagnostic programmer init messages are msg_pdbg, all
+other debug stuff (except warnings, which should be pmsg_pinfo or
+msg_perr) is msg_pspew.
+
+This makes "flashrom -p dummy -V" output a whole lot more readable
+(try it!). In case someone wants the full barfed output, it is
+possible to specify -VV instead of -V.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r841 | hailfinger | 2010-01-09 04:22:31 +0100 (Sat, 09 Jan 2010) | 11 lines
+
+The msg_* macros won't compile as is if you use more than one parameter
+(i.e. have a format string and a variable).
+There are two alternative styles: GNU or C99 variadic macros. While C99
+has limitations compared to the GNU extensions, these limitations do not
+affect our macros, so I decided to go with the standard way.
+
+I adjusted whitespace a bit to have aligned values (cosmetic change).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r840 | hailfinger | 2010-01-09 04:15:50 +0100 (Sat, 09 Jan 2010) | 9 lines
+
+Use address mask in probe_jedec. This allows us to have one common
+probe_jedec function instead of half a dozen wrappers.
+The trick here is to have FEATURE_ADDR_FULL==0 and thus default to
+unmasked addresses. That way, we only have to annotate chips which need
+small address masks.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r839 | hailfinger | 2010-01-09 03:24:17 +0100 (Sat, 09 Jan 2010) | 16 lines
+
+Use the register mapping feature bit.
+All functions which just call probe_jedec and then map flash registers
+are replaced by probe_jedec. All functions which call probe_jedec, map
+flash registers and do something else can at least eliminate mapping
+flash registers.
+Fix logic inversion in probe_jedec to map flash registers on success
+instead of on failure.
+Change a few TIMING_IGNORED to TIMING_FIXME where probe_jedec is used.
+
+Total savings: One probe function simplified, three probe functions
+eliminated.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r838 | hailfinger | 2010-01-08 22:18:08 +0100 (Fri, 08 Jan 2010) | 5 lines
+
+Add support for NetBSD.
+
+Signed-off-by: Jonathan A. Kollasch <jakllsch@kollasch.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r837 | hailfinger | 2010-01-07 22:23:45 +0100 (Thu, 07 Jan 2010) | 12 lines
+
+Fix Sharp LHF00L04.
+- Add eraseblock definitions
+- Use correct eraseblock sizes (the datasheet is a bit ambiguous)
+- Use correct probe function
+- Fill in probe timing
+
+There is a lot more stuff left to clean up, but at least probe and erase
+should work now.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r836 | snelson | 2010-01-07 21:21:58 +0100 (Thu, 07 Jan 2010) | 12 lines
+
+Converting fprintf(stderr), printf, and printf_debug into a common
+print interface for flashrom. It also changes so -VV will spit out
+highly verbose messages for debugging. This is a minimal patch to
+lessen impact a later patch will convert current printf messages to
+the new interface.
+
+Add file that was suppose to be committed with r835.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r835 | snelson | 2010-01-07 21:09:33 +0100 (Thu, 07 Jan 2010) | 9 lines
+
+Converting fprintf(stderr), printf, and printf_debug into a common print
+interface for flashrom. It also changes so -VV will spit out highly verbose
+messages for debugging. This is a minimal patch to lessen impact a later patch
+will convert current printf messages to the new interface.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r834 | hailfinger | 2010-01-07 04:32:17 +0100 (Thu, 07 Jan 2010) | 24 lines
+
+Programmer debug messages during programmer init/shutdown are useful
+because they print hardware settings and desired configuration. They
+help in getting a quick overview of hardware and software state on
+startup and shutdown.
+
+Programmer debug messages during flash chip access are mostly a
+distraction in logs and should only be enabled if someone is having
+problems which are suspected to stem from a programmer hardware or
+programmer software bug. Disable those messages by default, they can be
+reenabled by #define COMM_DEBUG in the affected programmer file.
+
+An added benefit is a tremendous size reduction in verbose
+probe/read/write/erase logs because only flash chip driver messages
+remain. In some cases, logs will shrink from 65 MB to 10 kB or less.
+
+The right(tm) fix would be two different debug levels (DEBUG and SPEW)
+and the ability to differentiate between programmer debug messages and
+flash chip debug messages. Until the design for the message printing
+infrastructure is finished, this is the best stop-gap measure we can
+get.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audioahcked@gmail.com>
+
+------------------------------------------------------------------------
+r833 | hailfinger | 2010-01-07 04:24:05 +0100 (Thu, 07 Jan 2010) | 15 lines
+
+Move the CLI related functions main() and cli_usage() to cli_classic.c
+and rename them accordingly. For now, main() just calls cli_classic(),
+but alternative frontends can be switched in main().
+Annotate remaining help texts with CLI dependency inside flashrom.c with
+a FIXME comment.
+
+Now people can go and create different frontends and be happy. Please
+note that any other frontend will have to sort of duplicate the probing
+code in cli_classic.c. Refactoring that part of the code is possible,
+but not easy because we still want to print instructive help messages
+for users.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r832 | oxygene | 2010-01-06 23:14:39 +0100 (Wed, 06 Jan 2010) | 5 lines
+
+buspiratespi support on mingw
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r831 | oxygene | 2010-01-06 20:09:40 +0100 (Wed, 06 Jan 2010) | 11 lines
+
+- replace the hand written serial input flush routine with the termios one.
+- serialport_discard_read isn't necessary anymore - it just wrapped
+  sp_flush_incoming with no extra value.
+- serialport_read and serialport_write would misbehave if read or write
+  didn't process everything in one go.
+- sp_flush_incoming should be #define'd out for FAKE_COMMUNICATION like
+  serialport_discard_read was
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r830 | hailfinger | 2010-01-06 17:09:10 +0100 (Wed, 06 Jan 2010) | 7 lines
+
+Move OS-dependent serial code from buspirate_spi.c to serial.c and
+rename a few functions to make it obvious that they are generic and not
+specific to the Bus Pirate.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
+
+------------------------------------------------------------------------
+r829 | hailfinger | 2010-01-06 11:21:00 +0100 (Wed, 06 Jan 2010) | 9 lines
+
+Some programmers (most notably FT2232SPI) use fallback_* and noop_*, but
+those functions lived inside internal.c and were unavailable if no
+PCI-based programmers were compiled in. Move those functions to the new
+file programmer.c.
+Thanks to Patrick Georgi for finding this.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
+
+------------------------------------------------------------------------
+r828 | snelson | 2010-01-04 18:15:23 +0100 (Mon, 04 Jan 2010) | 12 lines
+
+The patch converts jedec functions into mask-based generics which can be used
+for many chip provided the only changes are the addresses are converted from 
+0x5555/0x2AAA to 0x555/0x2AA or similar. The patch mostly changes jedec.c, but
+a few other files are changed because they use the jedec functions within
+their own functions.
+
+The patch also adds a copyright line to flashchips.c because of my recent work in converting AMD and Atmel chips to use struct erase_block.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r827 | stepan | 2010-01-04 00:50:28 +0100 (Mon, 04 Jan 2010) | 7 lines
+
+Drop multiple forwards to man page and add a single one more prominently.
+Drop usage information that is already mentioned in the man page.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r826 | mkarcher | 2010-01-03 16:09:17 +0100 (Sun, 03 Jan 2010) | 6 lines
+
+Fix Intel FWH decode size
+
+Fixes wrong detection of area decoded to the FWH interfaces.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r825 | stepan | 2010-01-03 15:40:30 +0100 (Sun, 03 Jan 2010) | 6 lines
+
+drop known broken email addresses.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r824 | snelson | 2009-12-24 17:54:21 +0100 (Thu, 24 Dec 2009) | 9 lines
+
+This patch shouldn't affect anything else in patchwork. It just splits
+$(OBJS) in Makefile into separate lists for Programmer, Chip, and CLI
+related files/objects. This should help later on figuring out where
+files may go for a libflashrom library.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r823 | hailfinger | 2009-12-24 04:33:11 +0100 (Thu, 24 Dec 2009) | 13 lines
+
+Only check for requested features in the Makefile.
+libpci is no longer required to build flashrom and will not be checked
+for if no PCI code is needed for the selected programmers.
+libftdi is no longer checked for if FT2232 support is not selected.
+
+With this patch, it is possible to build on pretty much every OS out
+there (including Windows) without altering the Makefile.
+Some gcc versions may need a CFLAGS override for a warning in
+dummyflasher.c, though.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r822 | hailfinger | 2009-12-24 04:11:55 +0100 (Thu, 24 Dec 2009) | 9 lines
+
+internal.c was always compiled in because it hosted the function
+internal_delay(). Move that function to udelay.c and compile internal.c
+only if really needed.
+physmap.c is only needed if the programmer is internal or a PCI card.
+Make its compilation conditional.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r821 | hailfinger | 2009-12-24 03:15:55 +0100 (Thu, 24 Dec 2009) | 11 lines
+
+Factor out CLI code by moving generic stuff out of main(). Add a generic
+programmer list output function to be used by alternative frontends.
+The interface between main() and doit is a hack and should get a clean
+design, but for now it serves the purpose of shortening main() by 120
+lines.
+The rest of main() needs to be refactored a bit more before moving
+main() away.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r820 | hailfinger | 2009-12-23 22:29:18 +0100 (Wed, 23 Dec 2009) | 5 lines
+
+Add VIA VT8233A identification, mark as tested.
+
+Signed-off-by: Ra?\195?\186l Soriano <GatoLoko@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r819 | snelson | 2009-12-23 18:05:59 +0100 (Wed, 23 Dec 2009) | 22 lines
+
+Convert the following chips to use struct eraseblock:
+AMIC_A29002B
+AMIC_A29002T
+EN_29F002B
+EN_29F002T
+MBM29F004BC
+MBM29F004TC
+MBM29F400BC
+MBM29F400TC
+MX_25L3205
+MX_25L6405
+MX_29F002B
+MX_29F002T
+
+
+Add block erasers for m29f400bt and mx29f002.
+Change programmer delays from 2 seconds to 10us in mx29f002 and am29f040b.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r818 | hailfinger | 2009-12-23 13:16:47 +0100 (Wed, 23 Dec 2009) | 7 lines
+
+Add blockwise erase to all supported chips of the SST25 family:
+SST25VF040.REMS, SST25VF040B, SST25VF040B.REMS, SST25VF080B,
+SST25VF016B, SST25VF032B
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r817 | hailfinger | 2009-12-23 13:02:55 +0100 (Wed, 23 Dec 2009) | 12 lines
+
+Convert the following chips to use struct eraseblock:
+AT25DF021, AT25DF041A, AT25DF081, AT25DF161, AT25DF321, AT25DF321A,
+AT25DF641, AT25F512B, AT25FS010, AT25FS040, AT26DF041, AT26DF081A,
+AT26DF161, AT26DF161A, AT26F004, AT29C512, AT29C010A, AT29C020,
+AT29C040A, AT49BV512, AT49F002(N), AT49F002(N)T
+
+A possible future patch would to add spi_block_erase_d7 to spi.c as an 
+alternate to spi_block_erase_20. Only some SPI chips support d7.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r816 | libv | 2009-12-23 04:01:36 +0100 (Wed, 23 Dec 2009) | 4 lines
+
+Board: Add MSI K8N Neo4-F
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Fraser Hanson <fraser.hanson@gmail.com>
+------------------------------------------------------------------------
+r815 | libv | 2009-12-23 01:54:26 +0100 (Wed, 23 Dec 2009) | 20 lines
+
+Chipset/Board: vt8237: Set All mem cycles to LPC in chipset enable.
+
+Only done for VT8237R (possibly needed for VT8237 too), VT8235 does
+not need this (even if the original bios does so: Asus A7V8X-MX SE,
+MSI KT4V were verified).
+
+This then opens a floodgate of cleanups in the board enables.
+* EPIA SP board enable vanishes, taking EPIA CN match with it.
+* Asus A7V8X-MX/Tyan S2498 board enable then equals
+  w836xx_memw_enable_2e
+* AOpen vKM400Am-S board enable then equals it8705_rom_write_enable
+* Epia M board enable becomes via_vt823x_gpio15_raise
+* Epia N board enable becomes via_vt823x_gpio9_raise
+* Asus M2V-MX board enable becomes via_vt823x_gpio5_raise
+* vt823x_gpio_set becomes via_vt823x_gpio_set, and now detects ISA
+  bridge itself, in concordance with intel ich and nvidia mcp gpio.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r814 | hailfinger | 2009-12-23 00:54:10 +0100 (Wed, 23 Dec 2009) | 5 lines
+
+Add a few FIXME comments to the generic SPI code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r813 | hailfinger | 2009-12-23 00:42:04 +0100 (Wed, 23 Dec 2009) | 16 lines
+
+SuperI/O detection now happens unconditionally and before the chipset
+enable. We could run it after chipset enable, but it definitely has to
+happen before board enable because the board enable usually accesses the
+SuperI/O.
+With this patch, it is possible to add a struct superio to the board
+enable table for more accurate matching in case subsystem IDs are
+ambiguous.
+This patch focuses on the generic infrastructure aspect and on support
+for IT8712F/IT8716F.
+
+Thanks go to Adrian Glaubitz and Ward Vandewege for testing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
+
+------------------------------------------------------------------------
+r812 | hailfinger | 2009-12-22 23:15:33 +0100 (Tue, 22 Dec 2009) | 19 lines
+
+Convert the following chips to use struct eraseblock:
+Am29F010A/B
+Am29F002(N)BB
+Am29F002(N)BT
+Am29F016D
+Am29F040B
+Am29F080B
+Am29LV040B
+Am29LV081B
+A29040B
+Pm29F002T
+Pm29F002B
+
+Change function signature of Am29 erase functions and JEDEC chip erase
+to be usable with block_erasers.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r811 | hailfinger | 2009-12-22 14:04:53 +0100 (Tue, 22 Dec 2009) | 7 lines
+
+Clarify comment about how to enter chip erase functions in
+struct block_eraser.
+Reported by Sean Nelson.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r810 | libv | 2009-12-22 14:04:13 +0100 (Tue, 22 Dec 2009) | 9 lines
+
+Boards: Fix several issues with nvidia_mcp_gpio_set.
+
+- CK804, MCP04, MCP2 use the isa bridges..
+- Newer nvidia mcp's do use the smbus controllers (Found by
+  Michael Karcher).
+- gpio line check breaks EPoX EP-8RDA3+, and should be wider.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+------------------------------------------------------------------------
+r809 | libv | 2009-12-21 16:30:46 +0100 (Mon, 21 Dec 2009) | 4 lines
+
+Chipset: Add support for Intel Poulsbo chipset.
+
+Signed-off-by: Adam Jurkowski <adam.jurkowski@kontron.pl>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+------------------------------------------------------------------------
+r808 | libv | 2009-12-18 09:37:55 +0100 (Fri, 18 Dec 2009) | 7 lines
+
+Boards: Add ECS K7S6A.
+
+The nulled second set of subsystem ids is correct, and this seems
+to be a unique match.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: spirals <spirals@eircom.net>
+------------------------------------------------------------------------
+r807 | hailfinger | 2009-12-17 17:20:26 +0100 (Thu, 17 Dec 2009) | 20 lines
+
+If the JEDEC Toggle Bit algorithm needs more than 2^20 loops, it is a
+good sign we should have used delays between toggle bit reads. Tell the
+user about this.  2^20 loops need roughly a second depending on flash
+bus speed. One reason for excessive loops can be a slow operation like
+erase.
+
+The Winbond W39V040C requires a 50 ms delay between toggle bit reads
+during erase according to the datasheet. Turns out a 2 ms delay is
+sufficient. Use a safety factor of 4 and default all erase operations to
+8 ms delay between toggle reads. This is short enough not to have a
+substantial negative impact on erase times, and should improve
+reliability.
+
+This patch addresses the excessive toggle behaviour (observed on some
+non-Winbond chips) and the toggle delay requirement (Winbond W39V040C).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Javier Ortega Conde (aka Malkavian) <malkavian666@gmail.com>
+Acked-By: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+
+------------------------------------------------------------------------
+r806 | hailfinger | 2009-12-17 16:20:01 +0100 (Thu, 17 Dec 2009) | 15 lines
+
+Use the maximum decode size infrastructure.
+- Detect max FWH size for Intel
+  631xESB/632xESB/3100/ICH6/ICH7/ICH8/ICH9/ICH10.
+- Move IDSEL override before decode size checking for the chipsets
+  listed above or flashrom will complain based on old values.
+- Adjust supported flash buses for the chipsets listed above (none of
+  them supports LPC or Parallel).
+- Detect max parallel size for AMD/National Semiconductor CS5530.
+- Adjust supported flash buses for CS5530/CS5530A.
+- Set board-specific max decode size for Elitegroup K7VTA3.
+- Set board-specific max decode size for Shuttle AK38N.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r805 | hailfinger | 2009-12-17 05:22:40 +0100 (Thu, 17 Dec 2009) | 8 lines
+
+probe_jedec() checks the delay value and issues programmer_delay based
+on the value except for delays between single chip_writeb.
+If a chip has zero probe_delay, delays between chip_writeb should be
+skipped as well.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r804 | hailfinger | 2009-12-17 05:21:12 +0100 (Thu, 17 Dec 2009) | 5 lines
+
+Remove nonexisting functions from chipdrivers.h
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r803 | libv | 2009-12-14 11:41:58 +0100 (Mon, 14 Dec 2009) | 15 lines
+
+Boards: Formalize intel piix4 gpo setting.
+
+The function intel_piix4_gpo_set includes proper gpo pin checking, and
+gpo pin enables when necessary.
+
+This is a leftover from soyo SY-6BA+III code that turned out to be
+unnecessary, but still used for the epox ep-bx3 board enable which it
+cleans up and clarifies.
+
+Difference to old code:
+* typical bios delay io port 0xEB now never gets touched.
+* pci config byte 0xB0 was not altered before.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r802 | hailfinger | 2009-12-14 05:24:42 +0100 (Mon, 14 Dec 2009) | 6 lines
+
+Use pci_fill_info() so device_class is valid.  This is needed on NetBSD
+and probably other non-Linux platforms.
+
+Signed-off-by: Jonathan A. Kollasch <jakllsch@kollasch.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r801 | hailfinger | 2009-12-14 05:11:12 +0100 (Mon, 14 Dec 2009) | 5 lines
+
+Mark ASRock M3A790GXH/128M as supported, no board enable needed.
+
+Signed-off-by: Zachary O Dillard <teathief@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r800 | hailfinger | 2009-12-14 05:04:18 +0100 (Mon, 14 Dec 2009) | 7 lines
+
+Fix eraseblock walking and add a few more checks to make sure such bugs
+get caught in the future. I found this bug during a code review.
+A consistency check for eraseblock definitions has been merged as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r799 | hailfinger | 2009-12-14 04:32:24 +0100 (Mon, 14 Dec 2009) | 14 lines
+
+Split hardware access, OS abstraction and chip drivers out of flash.h to
+get a better overview of what belongs where.
+
+This patch is only the first step, but it hopefully will make working
+with the code and especially porting to new platforms easier.
+
+Subsequent patches should move #includes for the newly created files
+hwaccess.h and chipdrivers.h from flash.h to the files which need them.
+Programmers should live in a separate header file as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Tested-by: Idwer Vollering <vidwer@gmail.com>
+
+------------------------------------------------------------------------
+r798 | hailfinger | 2009-12-14 04:07:31 +0100 (Mon, 14 Dec 2009) | 6 lines
+
+Don't print out supported PCI devices header if all following lines are
+excluded from build.
+
+Signed-off-by: Adam Jurkowski <adam.jurkowski@kontron.pl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r797 | hailfinger | 2009-12-13 23:28:00 +0100 (Sun, 13 Dec 2009) | 25 lines
+
+Internal (onboard) programming was the only feature which could not be
+disabled.
+Make various pieces of code conditional on support for internal
+programming. Code shared between PCI device programmers and onboard
+programming is now conditional as well.
+
+It is now possible to build only with dummy support:
+make CONFIG_INTERNAL=no CONFIG_NIC3COM=no CONFIG_SATASII=no
+CONFIG_DRKAISER=no CONFIG_SERPROG=no CONFIG_FT2232SPI=no
+
+This allows building for a specific use case only, and it also
+facilitates porting to a new architecture because it is possible to
+focus on highlevel code only.
+
+Note: Either internal or dummy programmer needs to be compiled in due to
+the current behaviour of always picking a default programmer if -p is
+not specified. Picking an arbitrary external programmer as default  
+wouldn't make sense.
+
+Build and runtime tested in all 1024 possible build combinations. The
+only failures are by design as mentioned above.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r796 | libv | 2009-12-09 12:39:02 +0100 (Wed, 09 Dec 2009) | 33 lines
+
+Boards: Tighten up ID match list.
+
+Tighten up board id match table in preparation of upcoming matching
+changes.
+
+Some boards are deliberately broken so that we will receive reports
+or can remove support later (for instance, for agami aruma, which,
+probably is no longer available in the wild).
+
+* Acorp 6A815EPD: make autodetectable.
+* Agami Aruma: remove bogus subsystem ids. Due to lacking secondary
+  main id, this match will break soon.
+* GIGABYTE GA-2761GXDK: Add secondary main id. Subsystem ids are not
+  possible as they are all copies of the main ids. Will still require
+  -m.
+* GIGABYTE GA-M57SLI-S4: add full set of subsystem ids. Will keep
+  match name for coreboot name matching.
+* GIGABYTE GA-M61P-S3: Add secondary main id. Remove name match.
+  Probably has good subsystem ids, but no info was found. So
+  deliberately broken match.
+* GIGABYTE GA-MA790FX-DQ6: pointless name match.
+* IBM x3455: add full ids, remove name match.
+* Kontron 986LCD-M: remove full id match as it is bogus. Kontron is
+  an embedded vendor and does not bother with subsystem ids, so
+  make this board name match only.
+* MSI MS-6590 (KT4 Ultra): remove name match.
+* MSI MS-7135 (K8N Neo3): add full id set, keep name match for
+  coreboot.
+* VIA EPIA-N/NL: remove name match.
+* VIA PC3500G: remove name match.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r795 | libv | 2009-12-09 08:53:01 +0100 (Wed, 09 Dec 2009) | 6 lines
+
+Boards: Add Asus M2V-MX.
+
+Expands via vt823x gpio support to also accept gpio5.
+
+Signed-off-by: David Bartley <dtbartle@csclub.uwaterloo.ca>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+------------------------------------------------------------------------
+r794 | libv | 2009-12-09 08:43:13 +0100 (Wed, 09 Dec 2009) | 10 lines
+
+Chipset: remove sis630 chipset enable for sis540.
+
+SiS630 chipset enable is equal to sis540 plus superio "poking".
+
+Superio poking equals IT8705F flash write enable, which is currently
+dealt with on a board by board basis in board_enable.c. Not all
+630 and newer based boards come with it8705/sis950 superios.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r793 | uwe | 2009-12-08 18:26:24 +0100 (Tue, 08 Dec 2009) | 6 lines
+
+Intel PIIX* chipsets only support parallel flash (no LPC/FWH/SPI).
+
+Signed-off-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r792 | libv | 2009-12-03 13:25:34 +0100 (Thu, 03 Dec 2009) | 7 lines
+
+Boards: Add general nVidia MCP gpio routine.
+
+Turns out that the AMD 8111 datasheet describes this bit of the MCP
+perfectly.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r791 | uwe | 2009-12-01 13:55:18 +0100 (Tue, 01 Dec 2009) | 15 lines
+
+Mark the following boards as OK (no board-enable needed):
+
+ - AsRock K8S8X (reported by Adrian Glaubitz <adrian.glaubitz@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2009-November/000937.html
+
+ - ASUS K8V-X SE (reported by Adrian Glaubitz <adrian.glaubitz@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2009-November/000965.html
+
+ - DFI Blood-Iron P35 T2RL (reported by Erno Vaurio <ernovaur@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2009-November/001059.html
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r790 | libv | 2009-11-29 02:19:25 +0100 (Sun, 29 Nov 2009) | 11 lines
+
+Board enable for Shuttle AK31.
+
+All AK31 versions, 1.x, 2.x and 3.x are supported by this board enable.
+Sadly this board can not be autodetected.
+
+Re-uses the epox ep 8k5a2 board enable, which now lost its check for
+the VT8235 ISA bridge and got renamed to w836xx_memw_enable_2e.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Mateusz Murawski <matowy@tlen.pl>
+------------------------------------------------------------------------
+r789 | libv | 2009-11-28 22:12:58 +0100 (Sat, 28 Nov 2009) | 7 lines
+
+Boards: Fix up MSI KT4V board enable.
+
+* Add autodetection and remove match strings.
+* Make use of vt823x_set_all_writes_to_lpc.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+------------------------------------------------------------------------
+r788 | libv | 2009-11-28 19:26:21 +0100 (Sat, 28 Nov 2009) | 4 lines
+
+Boards: Add Asus P4B266LM (Sony Vaio PCV-RX650).
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Allan Bjorklund <abjork@speakeasy.net>
+------------------------------------------------------------------------
+r787 | libv | 2009-11-28 19:16:31 +0100 (Sat, 28 Nov 2009) | 4 lines
+
+Boards: Add board match for Asrock P4i65GV.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r786 | libv | 2009-11-28 19:07:51 +0100 (Sat, 28 Nov 2009) | 7 lines
+
+Boards: provide enormous intel_ich_gpio_set function.
+
+This code sets gpio lines on random intel ichs. Detects all currently
+known intel ICHs, checks gpio lines, and then sets them accordingly.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+------------------------------------------------------------------------
+r785 | hailfinger | 2009-11-27 18:49:42 +0100 (Fri, 27 Nov 2009) | 31 lines
+
+Use common jedec functionality where appropriate. The deleted function
+in en29f002a.c is reintroduced as write_by_byte_jedec in jedec.c as it
+contains no chip-specific instructions. It is not yet used in other
+chip drivers, as key addresses (0x2AAA/0x5555) are often specified with
+less bits. After crosschecking datasheets, most of the fixmes can
+probably be resolved as indicated in them, causing significant code
+reduction.
+
+The common JEDEC code for bytewise programming does not program 0xFF at
+all.
+The chips that had a dedicated bytewise flash function which has been
+changed to write_jedec_1 thus changed flashing behaviour and the
+"write" test flag has been removed. This applies to:
+  AMD Am29F002BB/Am29F002NBB
+  AMD Am29F002BT/Am29F002NBT (TEST_OK_PREW before)
+  AMIC A29002B
+  AMIC A29002T (TEST_OK_PREW before)
+  EON EN29F002(A)(N)B
+  EON EN29F002(A)(N)T (TEST_OK_PREW before)
+  Macronix MX29F001B (TEST_OK_PREW before)
+  Macronix MX29F001T (TEST_OK_PREW before)
+  Macronix MX29F002B
+  Macronix MX29F002T (TEST_OK_PREW before)
+  Macronix MX29LV040
+
+Similar analysis should be performed for the read id stuff.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r784 | hailfinger | 2009-11-26 17:51:39 +0100 (Thu, 26 Nov 2009) | 12 lines
+
+Add support for Intel 3400 series / 5 series chipset.
+Found in Intel document 322170 (Intel 5 Series Chipset and Intel 3400
+Series Chipset Specification Update).
+According to http://pciids.sourceforge.net/ we probably should match all
+IDs from 0x3b00-0x3b1f, but so far I didn't find an Intel doc saying the
+same.
+If anybody has contacts at Intel and can check, I'd be happy to add the
+rest of the IDs.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r783 | hailfinger | 2009-11-26 15:50:52 +0100 (Thu, 26 Nov 2009) | 28 lines
+
+This patch removes the extremely dangerous unprotect_jedec function
+which is not used at all within flashrom code, and renames the
+misleadingly named protect_jedec function to start_program_jedec. Calls
+to protect_jedec after flashing are removed, because
+ a) on LPC chips, the command sent by protoct_jedec is not even in the
+datasheet and
+ b) on parallel chips, the block write command issued before already
+contained the software protection sequence, so software protection is
+definitely enabled.
+
+This patch also removes two clones of protect_jedec
+
+Background: JEDEC Software Data Protection started as an optional
+feature, which was disabled on the first single-voltage-flash chips. The
+software data protection is the need to prefix a write with a magic
+"write enable" command, while without write protection every write
+access into the chip's address space modifies flash content. This magic
+write enable command also tells the flash chip that the programmer
+obviously support sending write-enable commands and turns off the "any
+write modifies flash content" mode. There also exist a two-command (6
+writes) sequence that disables Software Data Protection completey, which
+should only ever be used to prepare updating with a device that can't
+handle software data protection.
+
+Signed-off-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r782 | hailfinger | 2009-11-26 12:05:01 +0100 (Thu, 26 Nov 2009) | 9 lines
+
+Add entries of W25x32 and W25x64. The model_ids are already in the
+header.
+
+W25x32 has been successfully probed.
+W25x64 is not available, the entry is based on the datasheet.
+
+Signed-off-by: Zheng Bao <zheng.bao@amd.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r781 | hailfinger | 2009-11-25 18:05:52 +0100 (Wed, 25 Nov 2009) | 5 lines
+
+Clarify a comment about verification routine usage.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r780 | hailfinger | 2009-11-25 17:58:17 +0100 (Wed, 25 Nov 2009) | 10 lines
+
+Reduce realloc syscall overhead for FT2232 and bitbang.
+
+FT2232 ran realloc() for every executed command. Start with a big enough
+buffer and don't touch buffer size unless it needs to grow.
+Bitbang was slightly better: It only ran realloc() if buffer size
+changed. Still, the solution above improves performance and reliability.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r779 | hailfinger | 2009-11-25 17:41:50 +0100 (Wed, 25 Nov 2009) | 7 lines
+
+jedec.c was missing error handling in a few cases. Fix.
+jedec.c error handling used double negation in too many places for no
+good reason. Clean up.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r778 | hailfinger | 2009-11-25 16:04:28 +0100 (Wed, 25 Nov 2009) | 7 lines
+
+Optimized write_sst_fwhub for safety and speed:
+Now uses block erase instead of chip erase. Also introduced auto skip
+feature.
+
+Signed-off-by: Adam Jurkowski <adam.jurkowski@kontron.pl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r777 | hailfinger | 2009-11-25 03:07:30 +0100 (Wed, 25 Nov 2009) | 9 lines
+
+Kill hardcoded block erase on ICH SPI.
+The existing code does not work for all SPI chips, and it just was a
+band-aid to cope with locked down chipsets back in a time when there was
+no eraseblock infrastructure.
+Basically, this unbreaks a few SPI chips on ICH.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+
+------------------------------------------------------------------------
+r776 | hailfinger | 2009-11-24 19:27:10 +0100 (Tue, 24 Nov 2009) | 19 lines
+
+Add the ability to set Bus Pirate SPI speed via the command line.
+Example usage:
+flashrom -p buspiratespi:spispeed=2.6MHz,dev=/dev/foo
+flashrom -p buspiratespi:dev=/dev/foo,spispeed=2.6M
+
+Refactor programmer option parsing (this allows cleanups in other
+programmers as well).
+
+Increase SPI read size from 8 to 12 bytes (current single-transaction
+limit of the Bus Pirate raw SPI protocol).
+
+Add Bus Pirate to the list of programmers supporting 4 byte RDID.
+
+Add Bus Pirate syntax to the man page.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Tested-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r775 | hailfinger | 2009-11-24 03:11:08 +0100 (Tue, 24 Nov 2009) | 6 lines
+
+Add Sanyo LF25FW203A support.
+This chip is sometimes labeled as 25FW203T.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r774 | hailfinger | 2009-11-24 03:08:11 +0100 (Tue, 24 Nov 2009) | 5 lines
+
+Add Generic SPI RDID detection for Sanyo chips.
+
+Signed-off-by: Sean Nelson <audiohacked@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r773 | hailfinger | 2009-11-24 01:23:33 +0100 (Tue, 24 Nov 2009) | 5 lines
+
+Revert debug compilation which was committed in r772 by accident.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r772 | hailfinger | 2009-11-24 01:20:03 +0100 (Tue, 24 Nov 2009) | 16 lines
+
+Add Bus Pirate SPI support to flashrom.
+
+The code should work on Linux/*BSD/MacOSX and relies on the serial code
+implementation in serial.c. Support for additional platforms (Windows)
+will have to be added to serial.c for this to work. For tests without a
+Bus Pirate (or with non-functional serial code) it is possible to
+#define FAKE_COMMUNICATION in buspirate_spi.c.
+Thanks to Sean Nelson for the SPI mode settings code. I tweaked it a bit
+to make configuration from a commandline easier should anybody want that
+feature.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Sean Nelson <audiohacked@gmail.com>
+Tested-by: Sean Nelson <audiohacked@gmail.com>
+
+------------------------------------------------------------------------
+r771 | hailfinger | 2009-11-23 20:20:11 +0100 (Mon, 23 Nov 2009) | 10 lines
+
+Move serial handling from serprog.c to serial.c.
+This is the first step in enabling platform independent serprog and it
+also allows other drivers to use serial port functionality without
+requiring serprog.
+
+Pure code move, no code changed.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r770 | hailfinger | 2009-11-23 13:55:31 +0100 (Mon, 23 Nov 2009) | 15 lines
+
+Add the ability to generate test patterns for write testing. This will
+be useful once we create a --test function for flashrom.
+
+The test patterns make it easy to find skipped and duplicated bytes, are
+human readable, and the first 8 of them have block numbers to detect
+aliasing or wraparounds. Current size limit for aliasing detection
+is 16 MByte, but since neither LPC nor FWH nor SPI chips exist with
+bigger sizes, this is reasonably safe.
+
+Detailed documentation is available as source code comments above the
+new function generate_testpattern().
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+
+------------------------------------------------------------------------
+r769 | hailfinger | 2009-11-22 02:33:40 +0100 (Sun, 22 Nov 2009) | 17 lines
+
+Pretty much everybody who used the FT2232 SPI driver in flashrom had
+problems with incorrect reads from time to time.
+One reason was that the hardware is pretty timing sensitive even for
+reads.
+
+The other reason was that the code silently ignored errors. This patch
+doesn't add any error recovery, but it will emit error messages if
+FT2232 communication goes wrong. That allows us to track down errors
+without investing hours in driver debugging.
+
+Thanks to Jeremy Buseman <naviathan@gmail.com> for testing. He found
+out that certain libftdi/libusb/kernel/hardware combinations drop
+some bytes without returning any error codes.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Paul Fox <pgf@laptop.org>
+
+------------------------------------------------------------------------
+r768 | hailfinger | 2009-11-21 12:02:48 +0100 (Sat, 21 Nov 2009) | 9 lines
+
+Bus Pirate support needs serial communication. Serprog already has such
+functionality, so it makes sense to share that.
+TODO: Factor out serial communication into a separate file, have that
+code be available even if serprog is not selected and make it portable
+(it is very Linux-centric right now).
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r767 | hailfinger | 2009-11-20 02:12:45 +0100 (Fri, 20 Nov 2009) | 11 lines
+
+If a chip is not on the RDID generic vendor list nor on the REMS
+specific ID list, flashrom will claim that no chip is there. Handle
+these cases gracefully. flashrom will ignore generic matches if a
+specific chip was found, so this will have no impact on supported chips,
+but help a lot for a first quick analysis by the user or developer. The
+only drawback is that unknown chips may be recognized multiple times
+until they are added to flashchips.[ch].
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Marc Jones <marcj303@gmail.com>
+
+------------------------------------------------------------------------
+r766 | hailfinger | 2009-11-17 10:57:34 +0100 (Tue, 17 Nov 2009) | 12 lines
+
+To prepare for libflashrom I wanted to make the main loop more readable
+and more correct and factor out stuff which can be useful in
+libflashrom.
+
+- Factor out printing of supported devices to print.c.
+- Adjust name of wiki printing function to fit the pattern.
+- Abort if the user specified --verify and --noverify at the same time.
+- Check for extra parameters which don't fit commandline syntax.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r765 | hailfinger | 2009-11-16 22:22:24 +0100 (Mon, 16 Nov 2009) | 7 lines
+
+Fix incorrect comment about wiki printing in Makefile.
+
+Spotted by Benjamin BELLEC <b.bellec@gmail.com>
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r764 | hailfinger | 2009-11-16 16:03:35 +0100 (Mon, 16 Nov 2009) | 9 lines
+
+If a SPI command taking an address does fail, we want to know the
+address for easier debugging.
+
+Vincent wrote: This patch provided help to debug the partial write on
+ICH in descriptor mode.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Vincent S. Cojot <openlook@cojot.name> 
+
+------------------------------------------------------------------------
+r763 | hailfinger | 2009-11-16 15:13:09 +0100 (Mon, 16 Nov 2009) | 9 lines
+
+Add URLs for boards ASUS K8V, ASUS K8V SE Deluxe, Elitegroup K7S5A.
+Add a note for ASUS M2N-E.
+Change "iff" to "if". Most people don't understand what "iff" means and
+the meaning of both words is close enough to hopefully give users the
+right idea.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r762 | hailfinger | 2009-11-16 15:05:13 +0100 (Mon, 16 Nov 2009) | 13 lines
+
+Retrieve the proper linker flags for libftdi via pkg-config and fall
+back if pkg-config isn't available or if it doesn't know libftdi.
+
+Fix $LIBS and $FEATURE_LIBS to honor dependency order.
+
+The original patch is from J?\195?\182rg, it has been updated by Carl-Daniel to
+work on the current tree and to have a fallback in case pkg-config is
+not available or not working.
+
+Signed-off-by: J?\195?\182rg Mayer <jmayer@loplof.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: J?\195?\182rg Mayer <jmayer@loplof.de>
+
+------------------------------------------------------------------------
+r761 | hailfinger | 2009-11-15 18:23:59 +0100 (Sun, 15 Nov 2009) | 5 lines
+
+svn:ignore .libdeps
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r760 | hailfinger | 2009-11-15 18:20:21 +0100 (Sun, 15 Nov 2009) | 10 lines
+
+Mark Elitegroup K7S5A as supported.
+Mark SiS 735 as supported.
+
+Remove "SiS" from the model number to avoid printing it twice.
+
+Reported by Adrian Glaubitz.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r759 | hailfinger | 2009-11-15 18:13:29 +0100 (Sun, 15 Nov 2009) | 18 lines
+
+Add support for every single SiS chipset out there.
+The two existing SiS chipset enables (compared to the 28 in this patch)
+were refactored, and one of them was fixed.
+
+A function to match PCI vendor/class combinations was added to generic
+code.
+
+Tested on the "Elitegroup K7S5A". Results are somewhat unexpected (some
+PCI settings seem to be inaccessible, but it still works).
+
+This is not based on any docs, but rather on detailed analysis
+of existing opensource code for some of the chipsets.
+
+Thanks to for Adrian Glaubitz testing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
+
+------------------------------------------------------------------------
+r758 | hailfinger | 2009-11-14 04:58:58 +0100 (Sat, 14 Nov 2009) | 9 lines
+
+Mark "Asus K8V" as supported. Reported by
+martin f krafft <madduck@madduck.net>
+
+Mark "Asus K8V SE Deluxe" as supported. Reported by
+Luke Dashjr <luke_coreboot@dashjr.org>
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r757 | hailfinger | 2009-11-14 04:48:33 +0100 (Sat, 14 Nov 2009) | 11 lines
+
+The automatic retry in write_page_write_jedec didn't retry flashing the
+correct range, essentially rendering the functionality useless. This
+patch simplifies the code and fixes the bug.
+
+Thanks to Luke Dashjr for testing.
+
+Mark Winbond W29C040P as supported.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luke Dashjr <luke_coreboot@dashjr.org>
+
+------------------------------------------------------------------------
+r756 | hailfinger | 2009-11-06 19:09:42 +0100 (Fri, 06 Nov 2009) | 5 lines
+
+Fix incorrect comment in SST49LF004A/B description.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r755 | hailfinger | 2009-10-31 02:53:09 +0100 (Sat, 31 Oct 2009) | 30 lines
+
+Add infrastructure to check and report to the user the maximum supported
+decode size for chipsets and tested mainboards.
+
+The rationale is to warn users when they, for example, try to flash
+a 512KB parallel flash chip but their chipset only supports 256KB,
+or they try to flash 512KB and the chipset _does_ theoretically
+support 512KB but their special board doesn't wire all address lines
+and thus supports only 256 KB ROM chips at maximum.
+
+This has cost Uwe hours of debugging on some board already, until he
+figured out what was going on. We should try warn our users where
+possible about this.
+
+The chipset and the chip may have more than one bus in common (e.g.
+SB600 and Pm49* can both speak LPC+FWH) and on SB600/SB7x0/SB8x0 there
+are different limits for LPC and FWH. The only way to tell the user
+about the exact circumstances is to spew error messages per bus.
+
+The code will issue a warning during probe (which does fail for some
+chips if the size is too big) and abort before the first real
+read/write/erase action. If no action is specified, the warning is
+printed anyway.
+That way, a user can find out why probe might not have worked, and will
+be stopped before he/she gets incorrect results.
+
+Add a bitcount function to the infrastructure.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r754 | hailfinger | 2009-10-30 22:12:39 +0100 (Fri, 30 Oct 2009) | 6 lines
+
+Adjust a help text for external PCI programmers to the new parameter
+scheme. Pointed out by Maciej Pijanka.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r753 | hailfinger | 2009-10-22 17:07:30 +0200 (Thu, 22 Oct 2009) | 12 lines
+
+Since we don't have any debug level printing infrastructure yet, I
+propose to kill the obnoxious debug message in ichspi.c which was added
+to check for correct PREOP handling. We know the code works fine (after
+getting a few reports over 100 MB long) and there's no point in keeping
+it around anymore.
+If there is any desire, we can reinstate it as print_spew or whatever
+once the debug level infrastructure is merged, but at that point we
+probably just are happy that the debug output isn't there anymore.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r752 | libv | 2009-10-21 14:05:50 +0200 (Wed, 21 Oct 2009) | 13 lines
+
+Board enable for Shuttle FN25 (SN25P).
+
+Shuttle SFF PC is SN25P, board FN25, AMD socket 939 with an nForce4
+chipset.
+
+Config register 0x92 on the ISA bridge needs to be cleared for TBL#
+to be raised. No information about individual bits of this register
+is currently available.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Ulf Mehlig <ulf@ufpa.br>
+
+
+------------------------------------------------------------------------
+r751 | hailfinger | 2009-10-19 20:15:36 +0200 (Mon, 19 Oct 2009) | 5 lines
+
+Remove confusing out-of-date comment.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r750 | uwe | 2009-10-06 22:25:48 +0200 (Tue, 06 Oct 2009) | 6 lines
+
+Add missing NVIDIA PCI IDs to wiki output.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r749 | uwe | 2009-10-06 22:23:29 +0200 (Tue, 06 Oct 2009) | 14 lines
+
+Mark the following boards as supported (no board-enable needed):
+
+ - MSI MS-6153 (reported by Uwe Hermann <uwe@hermann-uwe.de>)
+   Tested by me on hardware. The board decodes max. 256 KB.
+
+ - MSI MS-6156 (reported by Uwe Hermann <uwe@hermann-uwe.de>)
+   Tested by me on hardware. The board decodes max. 256 KB.
+
+Also, fix Dell PowerEdge 1850 name and add some more board URLs.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r748 | uwe | 2009-10-06 15:00:00 +0200 (Tue, 06 Oct 2009) | 6 lines
+
+Upon popular request, move board support tables to print.c.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r747 | libv | 2009-10-06 13:32:21 +0200 (Tue, 06 Oct 2009) | 7 lines
+
+Mark NVIDIA Nforce4/MCP04 as tested.
+
+Oops.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r746 | libv | 2009-10-05 20:46:35 +0200 (Mon, 05 Oct 2009) | 11 lines
+
+Board enable for EPoX EP-8RDA3+.
+
+SocketA + nForce2 + MCP2.
+
+Motherboard includes a second ethernet controller and an Agere
+firewire controller with valid subsystem ids, so these are used for
+matching the board.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Eddie Vanhove <moonraket@hotmail.com>
+
+------------------------------------------------------------------------
+r745 | libv | 2009-10-05 18:07:00 +0200 (Mon, 05 Oct 2009) | 12 lines
+
+Board enable for ASUS P5ND2-SLI Deluxe.
+
+This patch reorganises the board_ga_k8n_sli to create
+nvidia_mcp_gpio_raise, a more general routine to set these bits.
+Without docs, i can only assume that these memory area are gpio
+lines.
+
+Then it becomes easy to add support for this nForce4 SLI board.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Martin Szulecki <opensuse@sukimashita.com>
+
+------------------------------------------------------------------------
+r744 | libv | 2009-10-05 18:04:47 +0200 (Mon, 05 Oct 2009) | 8 lines
+
+Chipset support for the nVidia nForce 4.
+
+Add pciids for the new isa bridge, and hook it to the nforce2
+chipset enable.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Martin Szulecki <opensuse@sukimashita.com>
+
+------------------------------------------------------------------------
+r743 | hailfinger | 2009-10-03 19:08:02 +0200 (Sat, 03 Oct 2009) | 13 lines
+
+There is no need to tell people to install libz if flashrom doesn't need
+libz. So far, the only case where libz is needed is when a library
+(libpci) pulls in libz and even then it only happens if libpci is
+available in a static version only and said static version has libz
+requirements.
+
+Check for libpci separately and don't require libz if it isn't needed.
+
+Clarify the README.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r742 | uwe | 2009-10-01 20:40:02 +0200 (Thu, 01 Oct 2009) | 8 lines
+
+Cosmetics and small coding style fixes (trivial).
+
+Also, introduce BITMODE_BITBANG_SPI to eliminate a magic value.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r741 | hailfinger | 2009-10-01 16:51:25 +0200 (Thu, 01 Oct 2009) | 5 lines
+
+Make bitbang_spi naming consistent.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r740 | uwe | 2009-10-01 16:11:43 +0200 (Thu, 01 Oct 2009) | 8 lines
+
+Disable NVIDIA flashing support for now, erase/write is not properly
+working, yet. This needs more testing and investigation (partly timing
+related, it seems). Reads did work in multiple cases, though.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r739 | hailfinger | 2009-10-01 15:16:32 +0200 (Thu, 01 Oct 2009) | 5 lines
+
+Introduce proper error checking for SPI programming.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r738 | hailfinger | 2009-10-01 15:15:01 +0200 (Thu, 01 Oct 2009) | 12 lines
+
+Add comments about the meaning of block erase related struct flashchip
+members.
+Cosmetics: Place curly brackets on a common line.
+Add MX25V512 as alias name to MX25L512.
+Add MX25V8005 as alias name to MX25L8005.
+Add erase block definitions for
+MX25L2005, MX25L4005, MX25L8005, MX25L1605
+and change their status to TEST_OK_PRW where applicable.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r737 | uwe | 2009-09-30 20:29:55 +0200 (Wed, 30 Sep 2009) | 19 lines
+
+Add initial support for flashing some NVIDIA graphics cards.
+
+The new option is '-p gfxnvidia', rest of the interface is as usual.
+
+I tested a successful identify and read on a "RIVA TNT2 Model 64/Model 64 Pro"
+card for now, erase and write did NOT work properly so far!
+
+Please do not attempt to write/erase cards yet, unless you can recover!
+
+In addition to the NVIDIA handling code it was required to call
+programmer_shutdown() in a lot more places, otherwise the graphics card
+will be disabled in the init function, but never enabled again as the
+shutdown function is not called.
+The shutdown handling may be changed to use atexit() later.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+
+------------------------------------------------------------------------
+r736 | hailfinger | 2009-09-28 15:15:16 +0200 (Mon, 28 Sep 2009) | 11 lines
+
+This is the bitbanging SPI driver infrastructure.
+
+If you want support for a particular piece of hardware, just fill in
+a few functions in spi_bitbang_master_table. That's it.
+On top of this, the RayeR SPI flasher should be supportable in ~20 LOC.
+
+Tested, trace looks OK.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r735 | uwe | 2009-09-25 03:31:51 +0200 (Fri, 25 Sep 2009) | 6 lines
+
+Enable drkaiser programmer support in wiki output (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r734 | uwe | 2009-09-25 03:22:42 +0200 (Fri, 25 Sep 2009) | 21 lines
+
+Mark the following boards as OK:
+
+ - ASUS M3A78-EM (reported by Christian Heinz <christian.ch.heinz@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2009-September/000629.html
+ - MSI MS-7368 (K9AG Neo2-Digital) (reported by Joshua Roys <roysjosh@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2009-September/000632.html
+
+ - GIGABYTE GA-MA770T-UD3P (reported by Kevin Sopp <baraclese@googlemail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2009-September/000529.html
+   
+ - Elitegroup P6VAP-A+
+   Tested by Uwe Hermann <uwe@hermann-uwe.de> on hardware. Maximum supported
+   chip size in this board is 256 KB.
+   
+Small changes in print.c were required to adjust for longer board names.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r733 | uwe | 2009-09-25 03:09:18 +0200 (Fri, 25 Sep 2009) | 8 lines
+
+Mark the SST SST49LF003A/B as read-tested.
+
+See http://www.coreboot.org/pipermail/coreboot/2009-July/050675.html.
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r732 | uwe | 2009-09-25 03:05:06 +0200 (Fri, 25 Sep 2009) | 8 lines
+
+Add chipset support for VIA VT82C596 by adding a PCI ID (trivial).
+
+This is successfully tested by me on the Elitegroup P6VAP-A+ board.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r731 | hailfinger | 2009-09-24 00:01:33 +0200 (Thu, 24 Sep 2009) | 13 lines
+
+Switch SST49LF004A/B to block erase, remove the hack which simulated
+(unsupported) chip erase.
+Annotate SST49LF004B quirks for TBL#.
+
+Add TEST_OK_PRW which is useful when a PREW chip gets a new erase
+routine.
+
+Change a few erase function prototypes to use unsigned int instead of
+int.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r730 | hailfinger | 2009-09-23 23:58:34 +0200 (Wed, 23 Sep 2009) | 6 lines
+
+Change the status of the SST49LF020A to TEST_OK_PREW.
+I tested it on the Wyse Winterm S50 see attached test results.
+
+Signed-off-by: Nils Jacobs <njacobs8@hetnet.nl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r729 | hailfinger | 2009-09-23 04:09:23 +0200 (Wed, 23 Sep 2009) | 10 lines
+
+Enable flashrom on Wyse Winterm S50.
+
+On the Wyse Winterm S50 lspci doesn`t show the cs5536 hostbridge and so 
+flashrom doesn`t detect the cs5536.
+
+This patch is adding the cs5536 isa id [1022:2090] for chip detect.
+
+Signed-off-by: Nils Jacobs <njacobs8@hetnet.nl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r728 | hailfinger | 2009-09-23 04:05:12 +0200 (Wed, 23 Sep 2009) | 6 lines
+
+This enables flashing the Dell S1850 under Linux. 
+This code has been tested. 
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r727 | hailfinger | 2009-09-18 17:50:56 +0200 (Fri, 18 Sep 2009) | 14 lines
+
+The current ICH SPI preop handling is a hack which spews lots of
+warnings, but still yields correct results.
+With the multicommand infrastructure I introduced in r645, it became
+possible to integrate ICH SPI preopcodes cleanly into the flashrom
+design.
+
+The new code checks for every opcode in a multicommand array if it is a
+preopcode. If yes, it checks if the next opcode is associated with that
+preopcode and in that case it simply runs the opcode because the correct
+preopcode will be run automatically before the opcode.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: FENG Yu Ning <fengyuning1984@gmail.com>
+
+------------------------------------------------------------------------
+r726 | uwe | 2009-09-18 15:38:14 +0200 (Fri, 18 Sep 2009) | 8 lines
+
+Fix copy-paste errors by s/CONFIG_PRINT_WIKI/PRINT_WIKI_SUPPORT/.
+
+Trivial, and build-tested.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r725 | hailfinger | 2009-09-16 14:19:03 +0200 (Wed, 16 Sep 2009) | 11 lines
+
+Compile out wiki output on request and move wiki stuff into a separate
+file.
+This is useful for libflashrom (you don't need wiki output in a coreboot
+payload).
+
+Wiki output is now disabled by default. If you want to enable it, run
+make CONFIG_PRINT_WIKI=yes
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r724 | hailfinger | 2009-09-16 12:09:21 +0200 (Wed, 16 Sep 2009) | 14 lines
+
+Allow to exclude each of the external programmer drivers from being
+compiled in.
+
+Example make commandline if you want only internal programmers:
+make CONFIG_FT2232SPI=no CONFIG_SERPROG=no CONFIG_NIC3COM=no
+CONFIG_SATASII=no CONFIG_DRKAISER=no CONFIG_DUMMY=no
+
+Of course, all of the CONFIG_* symbols can be mixed and matched as
+needed. CONFIG_FT2232SPI is special because even if it is enabled, make
+will check if the headers are available and skip it otherwise.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r723 | stepan | 2009-09-16 10:26:59 +0200 (Wed, 16 Sep 2009) | 7 lines
+
+This patch cleans up flashrom so that it passes LLVM/clang's scan-build
+without warnings.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+
+------------------------------------------------------------------------
+r722 | stepan | 2009-09-16 10:18:08 +0200 (Wed, 16 Sep 2009) | 8 lines
+
+this patch fixes all 27 flashrom source code issues reported by
+LLVM/clang's scan-build (r79326, new build on the way).
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+
+This commit fixes only some of the issues, those that were
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r721 | uwe | 2009-09-09 02:58:19 +0200 (Wed, 09 Sep 2009) | 6 lines
+
+Mark Macronix MX29F001B as OK, tested by me on hardware.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r720 | uwe | 2009-09-09 02:55:13 +0200 (Wed, 09 Sep 2009) | 6 lines
+
+Replace pseudonym in drkaiser.c with real name.
+
+Signed-off-by: Joerg Fischer <turboj@gmx.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r719 | hailfinger | 2009-09-05 04:30:58 +0200 (Sat, 05 Sep 2009) | 66 lines
+
+This is a patch which stores eraseblock sizes and corresponding block
+erase functions in struct flashchip. I decided to fill in the info for a
+few chips to illustrate how this works both for uniform and non-uniform
+sector sizes.
+
+struct eraseblock{
+int size; /* Eraseblock size */
+int count; /* Number of contiguous blocks with that size */
+};
+
+struct eraseblock doesn't correspond with a single erase block, but with
+a group of contiguous erase blocks having the same size.
+Given a (top boot block) flash chip with the following weird, but
+real-life structure:
+
+top
+16384
+8192
+8192
+32768
+65536
+65536
+65536
+65536
+65536
+65536
+65536
+bottom
+
+we get the following encoding:
+{65536,7},{32768,1},{8192,2},{16384,1}
+
+Although the number of blocks is bigger than 4, the number of block
+groups is only 4. If you ever add some flash chips with more than 4
+contiguous block groups, the definition will not fit into the 4-member
+array anymore and gcc will recognize that and error out. No undetected
+overflow possible. In that case, you simply increase array size a bit.
+For modern flash chips with uniform erase block size, you only need one
+array member anyway.
+
+Of course data types will need to be changed if you ever get flash chips
+with more than 2^30 erase blocks, but even with the lowest known erase
+granularity of 256 bytes, these flash chips will have to have a size of
+a quarter Terabyte. I'm pretty confident we won't see such big EEPROMs
+in the near future (or at least not attached in a way that makes
+flashrom usable). For SPI chips, we even have a guaranteed safety factor
+of 4096 over the maximum SPI chip size (which is 2^24). And if such a
+big flash chip has uniform erase block size, you could even split it
+among the 4 array members. If you change int count to unsigned int
+count, the storable size doubles. So with a split and a slight change of
+data type, the maximum ROM chip size is 2 Terabytes.
+
+Since many chips have multiple block erase functions where the
+eraseblock layout depends on the block erase function, this patch
+couples the block erase functions with their eraseblock layouts.
+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];
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r718 | hailfinger | 2009-09-05 03:31:32 +0200 (Sat, 05 Sep 2009) | 6 lines
+
+Update probe timings for dozens of flash chips.
+
+Signed-off-by: Udu Ogah <putlinuxonit@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r717 | hailfinger | 2009-09-05 03:16:30 +0200 (Sat, 05 Sep 2009) | 22 lines
+
+Quite a few probe functions in flashrom are copies of probe_jedec with
+additional lock bit printing or other glue. Make them call probe_jedec
+instead.
+
+Use the correct reset sequence for 82802AB. Detailed explanation:
+The reset sequence before ID reading was correct, so ID always
+worked. But the reset sequence after ID reading was a copy-paste
+leftover from probe_jedec and didn't have any effect. I dug up
+flash_and_burn from the freebios-v1 tree and found out that 82802ab.c
+was indeed a copy of jedec.c with lots of experimental unannotated #if 0
+and #if 1.
+About the wait_82802ab change:
+Before the patch, wait_82802ab entered read status mode, switched to ID
+mode, then tried an incorrect and unsupported JEDEC command to exit ID
+mode. Nobody ever saw that this failed because all subsequent function
+calls had the correct reset sequence at the beginning.
+With the patch, wait_82802ab enters read status mode, then switches back
+to read mode with the official reset command.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r716 | hailfinger | 2009-09-05 03:12:07 +0200 (Sat, 05 Sep 2009) | 6 lines
+
+Not all systems have svnversion installed. Fall back to svn info if
+svnversion fails.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r715 | hailfinger | 2009-09-05 03:10:23 +0200 (Sat, 05 Sep 2009) | 7 lines
+
+Fix strict aliasing in serprog.
+Initialize the sockaddr,sockaddr_in union directly instead of running
+memset later.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r714 | stepan | 2009-09-04 15:57:07 +0200 (Fri, 04 Sep 2009) | 6 lines
+
+fix for gcc 4.4 strict aliasing rules.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r713 | uwe | 2009-09-03 01:27:45 +0200 (Thu, 03 Sep 2009) | 6 lines
+
+Add drkaiser.c which was accidentally omitted in the last commit.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r712 | uwe | 2009-09-03 01:00:46 +0200 (Thu, 03 Sep 2009) | 13 lines
+
+Add support for parallel flash on Dr. Kaiser PC-Waechter PCI devices.
+
+The vendor sold different designs under that name, the patch works with
+the one that has an Actel FPGA as PCI-to-Flash bridge.
+
+The Flash chip is a "Macronix MX29F001B" (128 KB, parallel) soldered
+directly to the PCB.
+Flash operations (PROBE, READ, ERASE, WRITE) work as expected.
+
+Signed-off-by: TURBO J <turboj@gmx.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r711 | uwe | 2009-09-03 00:09:00 +0200 (Thu, 03 Sep 2009) | 14 lines
+
+Standardize on using __func__ instead of __FUNCTION__.
+
+The __func__ variant is standardized in C99 and recommended to be
+used instead of __FUNCTION__ in the gcc info page.
+
+Only _very_ old versions of gcc did not know about __func__, but we've
+been using both __func__ and __FUNCTION__ for a long while now, and
+nobody complained about this, so all our users seem to use recent
+enough compilers.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r709 | hailfinger | 2009-09-02 15:47:36 +0200 (Wed, 02 Sep 2009) | 9 lines
+
+flashrom 0.9.1
+
+Please refer to the release notes for a high-level overview of all the
+amazing changes and added features since 0.9.0.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r708 | hailfinger | 2009-09-02 15:43:56 +0200 (Wed, 02 Sep 2009) | 8 lines
+
+Don't abort if chipset init failed because the failing init may have
+been a warning only.
+Even a failing chipset init (maybe due to unknown chipset) could still
+get us reasonable probe results or at least forced reads.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r707 | hailfinger | 2009-09-02 02:24:26 +0200 (Wed, 02 Sep 2009) | 6 lines
+
+Move the Asus A7V600-X out of the unsupported list. This is a followup
+to r705.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r706 | hailfinger | 2009-09-02 00:13:42 +0200 (Wed, 02 Sep 2009) | 5 lines
+
+Use correct name for SB700/SB710/SB750 instead of calling them SB700.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r705 | libv | 2009-09-01 23:22:23 +0200 (Tue, 01 Sep 2009) | 8 lines
+
+Board enable for Asus A7V600-X.
+
+Raises GP32 on IT8712F, and comes with a more general routine to set
+io lines on the IT8712F.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Udu Ogah <putlinuxonit@gmail.com>
+
+------------------------------------------------------------------------
+r704 | hailfinger | 2009-08-31 18:25:08 +0200 (Mon, 31 Aug 2009) | 10 lines
+
+With this patch, make tarball and make export still work as expected,
+but if you specify RELEASENAME=foo, then the directories and tarballs
+are named flashrom-foo instead of flashrom-0.9.0-r703.
+This makes release creation a lot easier. As an example, look at
+creating the 0.9.1 tarball:
+# make tarball RELEASENAME=0.9.1
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r703 | hailfinger | 2009-08-31 13:53:35 +0200 (Mon, 31 Aug 2009) | 7 lines
+
+Update bad board list and remove boards where either the chipset is not
+supported (not a board issue) or where we have no report in the
+archives.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r702 | uwe | 2009-08-30 16:14:59 +0200 (Sun, 30 Aug 2009) | 30 lines
+
+Board status updates.
+
+Marked as OK:
+
+ - ASUS A8V Deluxe (reported by Joachim Ernst <Joachim.Ernst@web.de>)
+   http://www.flashrom.org/pipermail/flashrom/2009-August/000448.html
+   Tested with r701.
+
+ - ASUS P5L-MX (reported by Vasiliy Vylegzhanin <6vasia@gmail.com>)
+   http://www.flashrom.org/pipermail/flashrom/2009-August/000446.html
+   Tested with v0.9.0.
+
+ - Abit Fatal1ty F-I90HD (reported by Joachim Ernst <joachim.ernst@web.de>)
+   http://www.flashrom.org/pipermail/flashrom/2009-August/000435.html
+
+ - Trigem Lomita (reported by Udu Ogah <putlinuxonit@gmail.com>)
+   Tested with r695.
+
+ - GIGABYTE GA-MA790GP-DS4H (reported by Ralph Loader <suckfish@ihug.co.nz>)
+   http://www.flashrom.org/pipermail/flashrom/2009-August/000414.html
+   http://www.flashrom.org/pipermail/flashrom/2009-August/000417.html
+
+ - GIGABYTE GA-MA78GPM-DS2H (reported by
+                             Erik Haugen Bakke <erik_hb_mlist@yahoo.com.au>)
+   http://www.flashrom.org/pipermail/flashrom/2009-August/000329.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r701 | hailfinger | 2009-08-24 15:29:25 +0200 (Mon, 24 Aug 2009) | 5 lines
+
+Update svn:ignore
+
+Signed-off-by: Joerg Mayer <jmayer@loplof.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r700 | hailfinger | 2009-08-24 15:24:52 +0200 (Mon, 24 Aug 2009) | 5 lines
+
+Update contact info.
+
+Signed-off-by: Joerg Mayer <jmayer@loplof.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r699 | hailfinger | 2009-08-24 03:47:33 +0200 (Mon, 24 Aug 2009) | 6 lines
+
+"3COM 3C90xB: PCI 10BASE-T (TPO)" (10b7:9004) works fine.
+Reported by Mark Panajotovic <panajotovic.marko@gmail.com>.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r698 | hailfinger | 2009-08-24 03:42:24 +0200 (Mon, 24 Aug 2009) | 5 lines
+
+Add support for MX29F001T and MX29F001B flash chips.
+
+Signed-off-by: Mark Panajotovic <panajotovic.marko@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r697 | hailfinger | 2009-08-24 03:34:48 +0200 (Mon, 24 Aug 2009) | 6 lines
+
+ASD AE29F2008 and Winbond W29C020C have the same ID. Reported by
+Mark Panajotovic <panajotovic.marko@gmail.com>.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r696 | hailfinger | 2009-08-21 19:26:13 +0200 (Fri, 21 Aug 2009) | 10 lines
+
+Anne Le Coq <annyvonne.le_coq@alcatel-lucent.fr> reported that flashrom
+didn't recognize her ICH9 LPC controller on the Green City
+Intel Customer Reference Board with ICH9 + Tylersburg Chipset.
+According to
+http://pci-ids.ucw.cz/read/PC/8086/2910 the ID 0x8086/0x2910 was used
+for engineering samples. No intel doc mentions this ID at all.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Anne Le Coq <annyvonne.le_coq@alcatel-lucent.fr>
+
+------------------------------------------------------------------------
+r695 | uwe | 2009-08-20 20:45:18 +0200 (Thu, 20 Aug 2009) | 24 lines
+
+Various board status updates (trivial).
+
+Mark the following boards as OK (no board-enable needed):
+
+ - Tyan S2466 (reported by Oliver Niesner <oli@servebbs.net>)
+   http://www.flashrom.org/pipermail/flashrom/2009-August/000211.html
+
+Mark the following boards as non-working for now:
+
+ - ASRock K7VT4A+ (reported by Udu Ogah <putlinuxonit@gmail.com>)
+   Chipset detect, but no chip.
+ - ASUS M2N68 (reported by Udu Ogah <putlinuxonit@gmail.com>)
+   Chipset detect, but no chip.
+ - ASUS A7V600-X (reported by Udu Ogah <putlinuxonit@gmail.com>)
+   Chipset and chip detected, writes don't work. Board-enable required.
+
+Also, add some missing board URLs and fix incorrect board names.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r694 | hailfinger | 2009-08-19 17:19:18 +0200 (Wed, 19 Aug 2009) | 10 lines
+
+Flashrom has the ability to use layout files with romentries, but this
+feature was not adapted to the programmer infrastructure and had
+undefined behaviour for flasher!=internal.
+The romentry handling had an off-by-one error which caused all copies to
+end up one byte short.
+Fix these issues.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r693 | hailfinger | 2009-08-19 17:03:28 +0200 (Wed, 19 Aug 2009) | 16 lines
+
+Current programmer parameter syntax is
+-p programmer=parameter
+Unfortunately, many parameters are of the form variable=val, so we get
+commandlines like this:
+flashrom -p it87spi=port=0x820
+and this looks horrible.
+
+Using : instead of = would make such parameters look better:
+flashrom -p it87spi:port=0x820
+
+As a side benefit, this patch mentions the programmer name in the error
+message if it is unknown.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r692 | hailfinger | 2009-08-19 15:55:34 +0200 (Wed, 19 Aug 2009) | 16 lines
+
+Disallow erase/write for known bad chips so people won't try without a
+clear understanding. Allow override with --force.
+
+If write/erase failed, warn the user to get help and not shutdown/reboot
+the computer.
+
+Warn that the result of a forced read is often garbage. Too many users
+believed that a forced read meant that everything was fine.
+
+Wait 1 second between erase and verify. This fixes a few reports where
+verify directly after erase had unpleasant side effects like corrupting
+flash or at least getting incorrect verify results.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r691 | hailfinger | 2009-08-19 15:27:58 +0200 (Wed, 19 Aug 2009) | 8 lines
+
+If FT2232H SPI is not enabled, it should be compiled out completely. We
+can't remove ft2232_spi.o from unconditional OBJS yet due to our
+makefile structure (make features), but this patch adds #ifdefs around
+all FT2232H code, so the net effect is the same.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r690 | hailfinger | 2009-08-19 12:46:23 +0200 (Wed, 19 Aug 2009) | 10 lines
+
+Support rdmsr/wrmsr operations on FreeBSD.
+
+So far, AMD Geode LX is the only user of this infrastructure. It needs
+/dev/cpu0 from ports/sysutils on FreeBSD during runtime on Geode LX.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: <putlinuxonit@gmail.com>
+
+------------------------------------------------------------------------
+r689 | hailfinger | 2009-08-19 01:51:22 +0200 (Wed, 19 Aug 2009) | 5 lines
+
+Add serprog documentation to the manpage.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r688 | hailfinger | 2009-08-19 01:50:14 +0200 (Wed, 19 Aug 2009) | 5 lines
+
+Tidy up docs before release. Don't mention coreboot.org without context.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r686 | hailfinger | 2009-08-17 18:30:53 +0200 (Mon, 17 Aug 2009) | 5 lines
+
+Fix compilation on Nexenta which is Ubuntu with a Solaris kernel.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r685 | hailfinger | 2009-08-14 01:23:37 +0200 (Fri, 14 Aug 2009) | 21 lines
+
+Allow the user to override FWH IDSEL on ICH6 and later.
+Usage:
+flashrom -p internal=fwh_idsel=0
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Log:
+flashrom v0.9.0-r670
+coreboot table found at 0xcf7f3c00.
+Vendor ID: KONTRON, part ID: 986LCD-M
+Found chipset "Intel ICH7/ICH7R", enabling flash write...
+Setting IDSEL=0 for top 8 MBOK.
+This chipset supports the following protocols: LPC,FWH.
+Disabling flash write protection for board "Kontron 986LCD-M"... OK.
+Calibrating delay loop... OK.
+Found chip "SST SST49LF016C" (2048 KB, FWH) at physical address
+0xffe00000.
+No operations were specified.
+
+Acked-by: Chris Kinney <cmkinne@sandia.gov>
+
+------------------------------------------------------------------------
+r684 | hailfinger | 2009-08-13 13:38:44 +0200 (Thu, 13 Aug 2009) | 8 lines
+
+Generate the usage message by walking the list of available programmers.
+This makes sure compiled out programmers are not listed.
+
+Tested, usage output is identical to the hardcoded variant.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r683 | stepan | 2009-08-12 20:25:24 +0200 (Wed, 12 Aug 2009) | 6 lines
+
+oops. MSR accesses in board specific code. I missed those.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r682 | libv | 2009-08-12 18:58:11 +0200 (Wed, 12 Aug 2009) | 10 lines
+
+Board enable for Asus P4P800-E Deluxe.
+
+Raises what seems to be gpio21.
+
+Uses host controller and Promise Raid Controller for a unique match.
+
+Signed-off-by:  Luc Verhaegen <libv@skynet.be>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+Tested-by: Bojan Radakovic <crnibojan@gmail.com>
+
+------------------------------------------------------------------------
+r681 | hailfinger | 2009-08-12 18:17:41 +0200 (Wed, 12 Aug 2009) | 12 lines
+
+Allow to compile out serprog completely. If CONFIG_SERPROG is not set,
+no stubs and no data of serprog will remain.
+
+Side benefit: This kills a few dozen lines of code.
+
+r678, r679 and r680 made this possible.
+Once "Only list available programers in usage()" is committed, even the
+usage message will be adjusted automatically.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r680 | hailfinger | 2009-08-12 16:34:35 +0200 (Wed, 12 Aug 2009) | 8 lines
+
+Use programmer.name to match the --programmer parameter instead of
+hardcoding the name of every single programmer in main().
+
+-p dummyfoo won't be mistaken for -p dummy anymore.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r679 | hailfinger | 2009-08-12 15:32:56 +0200 (Wed, 12 Aug 2009) | 7 lines
+
+Use a common parameter variable for all programmers. This allows us to
+reduce #ifdef clauses a lot if we compile out some programmers
+completely.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r678 | hailfinger | 2009-08-12 13:39:29 +0200 (Wed, 12 Aug 2009) | 12 lines
+
+FT2232 and IT87 programmers used functions of the dummy programmer
+instead of fallback functions. The dummy programmer is a "real"
+programmer with possible side effects and its functions should not be
+abused by other programmers. Make FT2232 and IT87 use official fallback
+functions instead.
+Create fallback_shutdown().
+Create fallback_chip_writeb().
+Convert the programmer #defines to an enum.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r677 | stepan | 2009-08-12 11:27:45 +0200 (Wed, 12 Aug 2009) | 4 lines
+
+Fix up MSR handling in flashrom to support more OSes than Linux. 
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r676 | stepan | 2009-08-11 14:15:39 +0200 (Tue, 11 Aug 2009) | 6 lines
+
+Make debug messages printf_debug(). 
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r675 | hailfinger | 2009-08-11 01:30:45 +0200 (Tue, 11 Aug 2009) | 8 lines
+
+Add ICH6,ICH7,ICH8,ICH9,ICH10 FWH IDSEL settings and flash decode
+settings to the debug output. This can help debug cases where the BIOS
+does not set up a correct flash decode for the given flash size.
+The Intel docs state that the decode applies to FWH and SPI flash.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Chris Kinney <cmkinne@sandia.gov>
+
+------------------------------------------------------------------------
+r674 | hailfinger | 2009-08-10 12:14:23 +0200 (Mon, 10 Aug 2009) | 15 lines
+
+Add IDs for 25 AMD chips, 11 Hynix chips, 8 Sharp chips, and their
+variants.
+AM29DL400BB, AM29DL400BT, AM29DL800BB, AM29DL800BT, AM29F004BB
+AM29F004BT, AM29F200BB, AM29F200BT, AM29F400BB, AM29F400BT
+AM29F800BB, AM29F800BT, AM29LV002BB, AM29LV002BT, AM29LV004BB
+AM29LV004BT, AM29LV008BB, AM29LV008BT, AM29LV080B, AM29LV200BB
+AM29LV200BT, AM29LV400BB, AM29LV400BT, AM29LV800BB, AM29LV800BT
+HY29F002, HY29F040A, HY29F080, HY29F400B, HY29F400T, HY29F800B
+HY29F800T, HY29LV400B, HY29LV400T, HY29LV800B, HY29LV800T
+LH28F008BJxxPB, LH28F008BJxxPT, LH28F008SA, LH28F008SC, LH28F800BVxxBTL
+LH28F800BVxxBV, LH28F800BVxxTV, LHF00L02
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r673 | hailfinger | 2009-08-10 04:29:21 +0200 (Mon, 10 Aug 2009) | 8 lines
+
+Some SPI chip drivers and the generic 1-byte SPI chip write functions
+didn't include the automatic erase present in other chip drivers. Since
+the majority is definitely auto-erase, change the remaining
+explicit-erase cases to be auto-erase as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carlos Arnau Perez <cemede@gmail.com>
+
+------------------------------------------------------------------------
+r672 | hailfinger | 2009-08-09 23:50:24 +0200 (Sun, 09 Aug 2009) | 7 lines
+
+Releasing IO permissions was done by hand everywhere. Use a proper
+abstraction.
+Kill unneeded #include statements.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r671 | hailfinger | 2009-08-09 14:44:08 +0200 (Sun, 09 Aug 2009) | 7 lines
+
+Remove unnecessary #include files.
+Serprog compilation is now controlled by a Makefile variable.
+Replace munmap with physunmap where appropriate.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r670 | hailfinger | 2009-08-03 11:35:20 +0200 (Mon, 03 Aug 2009) | 5 lines
+
+Fix SPI multicommand endless loop in default_spi_send_multicommand.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r669 | stepan | 2009-07-30 15:32:26 +0200 (Thu, 30 Jul 2009) | 7 lines
+
+The project's new home is flashrom.org now. Change all occurences in the
+source code and documentation accordingly.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r668 | stepan | 2009-07-30 15:30:17 +0200 (Thu, 30 Jul 2009) | 10 lines
+
+Boards with coreboot have a cbtable containing vendor and board name.
+flashrom tries to match these with board enable entries in its database.
+If no such board enable entry exists because the board doesn't need one,
+flashrom complains. Silence that complaint.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Slightly updated and
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r667 | hailfinger | 2009-07-24 15:59:27 +0200 (Fri, 24 Jul 2009) | 60 lines
+
+Add IDs for 51 new flash chips:
+
+AMIC A29400T
+AMIC A29400U
+AMIC A29800T
+AMIC A29800U
+AMIC A29L004T
+AMIC A29L004U
+AMIC A29L008T
+AMIC A29L008U
+AMIC A29L040
+Macronix MX29F004B
+Macronix MX29F004T
+Macronix MX29F022T
+Macronix MX29F080
+Macronix MX29F800B
+Macronix MX29F800T
+Macronix MX29LV081
+Spansion MBM29DL400BC
+Spansion MBM29DL400TC
+Spansion MBM29DL800BA
+Spansion MBM29DL800TA
+Spansion MBM29F002BC
+Spansion MBM29F002TC
+Spansion MBM29F040C
+Spansion MBM29F080A
+Spansion MBM29F200BC
+Spansion MBM29F200TC
+Spansion MBM29F800BA
+Spansion MBM29F800TA
+Spansion MBM29LV002BC
+Spansion MBM29LV002TC
+Spansion MBM29LV004BC
+Spansion MBM29LV004TC
+Spansion MBM29LV008BA
+Spansion MBM29LV008TA
+Spansion MBM29LV080A
+Spansion MBM29LV200BC
+Spansion MBM29LV200TC
+Spansion MBM29LV400BC
+Spansion MBM29LV400TC
+Spansion MBM29LV800BA
+Spansion MBM29LV800TA
+SST 49LF030A
+ST M29F080
+ST M29F200BB
+ST M29F200BT
+ST M29F400BB
+ST M29F800DB
+ST M29F800DT
+Winbond W39L020
+Winbond W39L040
+Winbond W49F020
+
+These still need to be added to flashchips.c, but if we ever encounter
+them in real life, the ID->name lookup will be a lot easier.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r666 | hailfinger | 2009-07-24 14:18:54 +0200 (Fri, 24 Jul 2009) | 5 lines
+
+If writing failed, verifying is pointless. Abort instead.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Oliver Niesner <oli@rhce.servebbs.net>
+
+------------------------------------------------------------------------
+r665 | hailfinger | 2009-07-23 14:42:01 +0200 (Thu, 23 Jul 2009) | 5 lines
+
+Improve flashchip comments to be more readable and precise.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r664 | hailfinger | 2009-07-23 03:44:38 +0200 (Thu, 23 Jul 2009) | 6 lines
+
+Fix erase for SST49LF020A. The chip supports multiple erase functions,
+but the function we use has an eraseblock size of 4k.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r663 | hailfinger | 2009-07-23 03:42:56 +0200 (Thu, 23 Jul 2009) | 8 lines
+
+Continue erase/write verification after the first error.
+The first error is printed in detail and all subsequent errors are
+listed in statistics. This allows users to check if there was just one
+error or if the failure was widespread.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r662 | hailfinger | 2009-07-23 03:40:20 +0200 (Thu, 23 Jul 2009) | 9 lines
+
+Add support for old ST M25P05/M25P10 chips which only respond to the RES
+command and not the RDID command.
+
+Unfortunately, either the datasheets are wrong or both chips have
+exactly the same ID.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r661 | hailfinger | 2009-07-23 03:36:08 +0200 (Thu, 23 Jul 2009) | 26 lines
+
+This is a workaround for a bug in SB600 and SB700. If we only send an
+opcode and no additional data/address, the SPI controller will read one
+byte too few from the chip. Basically, the last byte of the chip
+response is discarded and will not end up in the FIFO. It is unclear if
+the CS# line is set high too early as well.
+That hardware bug is undocumented as of now, but I'm working with AMD to
+add a detailed description of it to the errata.
+
+Add loads of additional debugging to SB600/SB700 init.
+
+Add explanatory comments for unintuitive code flow.
+
+Thanks go to Uwe for testing quite a few iterations of the patch.
+
+Kill the SB600 flash chip status register special case, which was a
+somewhat misguided workaround for that hardware erratum.
+
+Note for future added features in the SB600 SPI driver: It may be
+possible to read up to 15 bytes of command response with overlapping
+reads due to the ring buffer design of the FIFO if the command can be
+repeated without ill effects. Same for skipping up to 7 bytes between
+command and response.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r660 | hailfinger | 2009-07-23 03:33:43 +0200 (Thu, 23 Jul 2009) | 12 lines
+
+Verbose probe output is split across multiple lines for some probe
+functions. This makes visual inspection and grepping a lot harder than
+necessary.
+Remove line breaks where appropriate.
+Some error messages should end up on stderr instead of just being
+displayed in verbose mode.
+
+Thanks to Maciej Pijanka for testing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r659 | hailfinger | 2009-07-22 22:13:00 +0200 (Wed, 22 Jul 2009) | 5 lines
+
+Eliminate version string duplication.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r658 | hailfinger | 2009-07-22 22:09:28 +0200 (Wed, 22 Jul 2009) | 5 lines
+
+Convert SPI write status register to multicommand infrastructure.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r657 | hailfinger | 2009-07-22 17:36:50 +0200 (Wed, 22 Jul 2009) | 12 lines
+
+Replace most of the switch cases in the spi code with lookup on a struct
+instead. This brings the SPI code in line with the generic programmer
+infrastructure.
+
+This patch is a reworked version of a patch by Jakob Bornecrantz.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Signed-off-by: Jakob Bornecrantz <wallbraker@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Jakob Bornecrantz <wallbraker@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r656 | hailfinger | 2009-07-21 15:02:59 +0200 (Tue, 21 Jul 2009) | 11 lines
+
+Support for an external serial flasher protocol.
+Supports RS-232, USB serial converters (untested) and TCP streams.
+
+The protocol specification is in serprog-protocol.txt
+
+There will be tweaks to the code and maybe the protocol in the future,
+so the API is not set in stone yet.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r655 | libv | 2009-07-21 03:44:45 +0200 (Tue, 21 Jul 2009) | 7 lines
+
+Board enable for Aopen VKM400 AM-S.
+
+This board is a VIA KM400 and VT8237 and IT8705F superio.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by:  Scott Johnson <scott@gnuveau.net>
+
+------------------------------------------------------------------------
+r654 | hailfinger | 2009-07-20 17:21:18 +0200 (Mon, 20 Jul 2009) | 10 lines
+
+Reset SST49LF016C after erase to exit the read status register mode.
+Without this, all reads after erase will return 0x80 instead of the real
+memory contents.
+
+Thanks to Michael Melcher for testing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Michael Melcher <Michael.Melcher82@googlemail.com>
+
+------------------------------------------------------------------------
+r653 | hailfinger | 2009-07-14 12:26:56 +0200 (Tue, 14 Jul 2009) | 9 lines
+
+Use a distinct return code for SPI commands with unsupported/invalid
+length.
+Some drivers support only a few combinations of read/write length and
+return error otherwise. Having a distinct return code for this error
+means we can handle it in upper layers.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r652 | libv | 2009-07-13 14:40:17 +0200 (Mon, 13 Jul 2009) | 10 lines
+
+Board enable for Asus A7V8X.
+
+GP51 is attached to both WP# and TBL#.
+
+Made possible by the quick response of ITE when asked for information,
+and the tenacious testing of Glenn Mueller.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Glenn Mueller <mechwarrior5@hotmail.com>
+
+------------------------------------------------------------------------
+r651 | hailfinger | 2009-07-12 14:06:18 +0200 (Sun, 12 Jul 2009) | 7 lines
+
+Convert SPI byte program to use the multicommand infrastructure.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested it on Epia-m700 worked okay.
+Acked-by: Jakob Bornecrantz <wallbraker@gmail.com>
+Tested-by: Jakob Bornecrantz <wallbraker@gmail.com>
+
+------------------------------------------------------------------------
+r650 | hailfinger | 2009-07-12 00:26:52 +0200 (Sun, 12 Jul 2009) | 10 lines
+
+Convert SPI block erase to use the multicommand infrastructure.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Jakob writes:
+Tested it on my EPIA-m700 and it worked nice. Also double checked that
+one of the changed functions actually ran.
+Acked-by: Jakob Bornecrantz <wallbraker@gmail.com>
+Tested-by: Jakob Bornecrantz <wallbraker@gmail.com>
+
+------------------------------------------------------------------------
+r649 | uwe | 2009-07-12 00:17:28 +0200 (Sun, 12 Jul 2009) | 23 lines
+
+Fix incorrect manpage (trivial).
+
+The flashrom manpage currently says "-w, --write: Write file into flash
+ROM (default when <file> is specified)". This is no longer true for recent
+flashrom versions, which only write if you explicitly use the -w option.
+
+Proof:
+
+$ flashrom coreboot.rom
+flashrom v0.9.0-r631
+No coreboot table found.
+Found chipset "Intel ICH7/ICH7R", enabling flash write... OK.
+Found board "Kontron 986LCD-M", enabling flash write... OK.
+Calibrating delay loop... OK.
+Found chip "PMC Pm49FL004" (512 KB) at physical address 0xfff80000.
+No operations were specified.
+
+Thus, fix manpage accordingly.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r648 | hailfinger | 2009-07-11 21:39:11 +0200 (Sat, 11 Jul 2009) | 7 lines
+
+Add Winbond W25X16.
+Tested probing and reading only. The chip ID was already
+in flashchips.h.
+
+Signed-off-by: Hector Martin <hector@marcansoft.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r647 | hailfinger | 2009-07-11 21:28:36 +0200 (Sat, 11 Jul 2009) | 9 lines
+
+Convert SPI chip erase to use the multicommand infrastructure.
+
+Once the ICH/VIA SPI driver is converted to multicommand, a lot of hacks
+can disappear.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Jakob Bornecrantz <wallbraker@gmail.com>
+Acked-by: Jakob Bornecrantz <wallbraker@gmail.com>
+
+------------------------------------------------------------------------
+r646 | hailfinger | 2009-07-11 20:05:42 +0200 (Sat, 11 Jul 2009) | 10 lines
+
+Add an optional flash port parameter for IT87* SPI controllers in
+standalone programmer mode. If the parameter is set, the IT87* SPI
+driver will set the I/O base port of the IT87* SPI controller interface
+to the port specified in the parameter.
+Usage:
+flashrom -p it87spi=port=0x820
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r645 | hailfinger | 2009-07-10 23:08:55 +0200 (Fri, 10 Jul 2009) | 24 lines
+
+Add SPI multicommand infrastructure.
+
+Some SPI opcodes need to be sent in direct succession after each other
+without any chip deselect happening in between. A prominent example is
+WREN (Write Enable) directly before PP (Page Program). Intel calls the
+first opcode in such a row "preopcode".
+
+Right now, we ignore the direct succession requirement completely and it
+works pretty well because most onboard SPI masters have a timing or
+heuristics which make the problem disappear.
+The FT2232 SPI flasher is different. Since it is an external flasher,
+timing is very different to what we can expect from onboard flashers and
+this leads to failure at slow speeds.
+
+This patch allows any function to submit multiple SPI commands in a
+stream to any flasher. Support in the individual flashers isn't
+implemented yet, so there is one generic function which passes the each
+command in the stream one-by-one to the command functions of the
+selected SPI flash driver.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Jakob Bornecrantz <wallbraker@gmail.com>
+Tested-by: Jakob Bornecrantz <wallbraker@gmail.com>
+
+------------------------------------------------------------------------
+r644 | hailfinger | 2009-07-10 22:19:48 +0200 (Fri, 10 Jul 2009) | 11 lines
+
+Change tarball compression from gzip to bzip2.
+
+Set the user and group of all files to root for tar versions which
+support it. Add explanatory comments for supporting that feature with
+other tar versions.
+
+Use LC_ALL instead of LANG everywhere.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r643 | libv | 2009-07-08 16:50:36 +0200 (Wed, 08 Jul 2009) | 13 lines
+
+W39V040B: Flag Erase/Write as bad.
+
+Chip has now been properly tested in both my Jetway J7F5M and my EPIA-SP
+(known good board). Erase and write fail. Mark these operations as bad
+until i or someone else have time to fix this.
+
+Reported by Arvid Brodin <arvidb@kth.se>.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+M    flashchips.c
+
+------------------------------------------------------------------------
+r642 | libv | 2009-07-07 00:58:46 +0200 (Tue, 07 Jul 2009) | 7 lines
+
+Board enable for Abit IP35.
+
+Raise GPIO 16 on ICH9R LPC Interface.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Richie Ward <RichieS@GMail.com>
+
+------------------------------------------------------------------------
+r641 | uwe | 2009-07-04 17:10:41 +0200 (Sat, 04 Jul 2009) | 6 lines
+
+Add more URLs and board notes, fix a typo (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r640 | uwe | 2009-07-04 01:51:19 +0200 (Sat, 04 Jul 2009) | 12 lines
+
+Some flashrom printing changes:
+ - Also print URLs of boards with board-enables.
+ - Mark known-bad operations for chips red in the wiki.
+ - Clarifiy a wiki message a bit.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r639 | uwe | 2009-07-03 19:12:05 +0200 (Fri, 03 Jul 2009) | 37 lines
+
+Mark the following boards as working:
+
+ - VIA EPIA-M700 (reported by Jakob Bornecrantz <wallbraker@gmail.com>)
+   http://www.coreboot.org/pipermail/coreboot/2009-July/050416.html
+
+ - GIGABYTE GA-EX58-UD4P (reported by Warren Turkal <wt@penguintechs.org>)
+   http://www.coreboot.org/pipermail/coreboot/2009-June/050199.html
+
+Mark as non-working:
+
+ - ASUS Eee PC 701 4G (reported by Uwe Hermann <uwe@hermann-uwe.de>)
+   There seems to be some SPI flash translation layer, likey done by the
+   embedded controller on the laptop (ENE KB3310).
+   The BIOS chip in this Eee PC model is Winbond 25X40VSIG btw.
+   More info: http://beta.ivancover.com/wiki/index.php/Eee_PC_Research
+
+Mark this chip as tested:
+
+ - ST M25P40 (reported by Jakob Bornecrantz <wallbraker@gmail.com>)
+   http://www.coreboot.org/pipermail/coreboot/2009-July/050416.html
+
+Other:
+
+ - Make the "Albatron PM266A" board detection print "Albatron PM266A*" as this
+   enable will actually work for other PM266A* boards according to libv.
+   However, the code was actually tested on "Albatron PM266A Pro".
+
+ - Add some more board URLs / notes.
+
+ - s/BioStar/Biostar/ as per vendor website.
+
+ - Fix typo in print.c: s/A7V8-MX SE/A7V8X-MX SE/.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r638 | hailfinger | 2009-07-01 02:02:23 +0200 (Wed, 01 Jul 2009) | 7 lines
+
+ft2232_spi: Allow runtime selection of FT2232H vs. FT4232H and
+interface A vs. B.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Jakob Bornecrantz <wallbraker@gmail.com>
+Acked-by: Jakob Bornecrantz <wallbraker@gmail.com>
+
+------------------------------------------------------------------------
+r637 | hailfinger | 2009-06-30 14:41:00 +0200 (Tue, 30 Jun 2009) | 7 lines
+
+Add changelog for make export and make tarball.
+
+Thanks to Uwe for the suggestion.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r636 | uwe | 2009-06-29 01:26:37 +0200 (Mon, 29 Jun 2009) | 14 lines
+
+Random minor flashrom fixes:
+
+ - Properly escape '-' chars in manpage.
+ - Fix typo in chipset_enable.c.
+
+ - Drop useless 'return' in chip_readn().
+
+ - Random other whitespace or cosmetic fixes.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r635 | uwe | 2009-06-28 23:47:57 +0200 (Sun, 28 Jun 2009) | 7 lines
+
+Print the bus type(s) of both chipset and chip in the flashrom
+output (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r634 | hailfinger | 2009-06-28 21:19:25 +0200 (Sun, 28 Jun 2009) | 6 lines
+
+Fix all NONSPI bustypes in flashchips.c.
+Also noted as a comment if an FWH/LPC chip supports A/A Mux mode.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r633 | hailfinger | 2009-06-28 12:57:58 +0200 (Sun, 28 Jun 2009) | 10 lines
+
+Handle programmer init errors and abort. If the programmer didn't
+initialize correctly, it is pointless to continue.
+
+Fix standalone IT87* SPI init to set flashbus to NONE if no IT87* SPI
+communication is possible.
+Print the I/O port detected by the IT87* SPI code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r632 | hailfinger | 2009-06-25 15:57:31 +0200 (Thu, 25 Jun 2009) | 11 lines
+
+Change chip_readb in loop to use verify_range in
+write_page_write_jedec (jedec.c).
+
+Tested by Urja Rannikko with external flasher.
+Tested by Uwe Hermann with onboard flash.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r631 | uwe | 2009-06-24 19:31:08 +0200 (Wed, 24 Jun 2009) | 10 lines
+
+Always verify write operations automatically.
+
+Should this be undesireable because of speed reasons, --noverify can be
+used to suppress an auto-verify.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Harald Gutmann <harald.gutmann@gmx.net>
+
+
+------------------------------------------------------------------------
+r630 | hailfinger | 2009-06-24 10:28:39 +0200 (Wed, 24 Jun 2009) | 11 lines
+
+Check result of all SPI erase functions.
+Since block erase functions do not know the block length (it's not
+specified in any standard), block erase functions now get an additional
+parameter blocklen. This enables flashrom to verify the erase result for
+block erase functions at correct boundaries.
+
+Tested by Uwe on SB600.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r629 | hailfinger | 2009-06-24 10:20:45 +0200 (Wed, 24 Jun 2009) | 12 lines
+
+Use correct abstraction for verify_range(). The new abstraction can
+handle out-of-band chip communication protocols as well.
+The old abstraction caused spurious false positives for erase on SPI and
+spurious false negatives for verify on SPI.
+
+Make verify_flash() use verify_range().
+
+Tested by Uwe on SB600.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r628 | hailfinger | 2009-06-24 10:18:38 +0200 (Wed, 24 Jun 2009) | 6 lines
+
+Remove duplicated [file] from usage help. A file is already specified
+directly in conjunction for -r/-w/-v.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r627 | uwe | 2009-06-23 22:27:33 +0200 (Tue, 23 Jun 2009) | 12 lines
+
+Mark the following boards as working OK:
+
+ - ASUS P5KC (reported by Andrei Pavlov <pavlov.andrei@rambler.ru>)
+ - GIGABYTE GA-EP35-DS3L (reported by Alexander Gordeev <lasaine@lvk.cs.msu.su>)
+Add a few more URLs.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r626 | hailfinger | 2009-06-23 13:48:37 +0200 (Tue, 23 Jun 2009) | 6 lines
+
+The makefile rules for %.o and flashrom.o are identical. Let %.o handle
+flashrom.o as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r625 | hailfinger | 2009-06-23 13:33:43 +0200 (Tue, 23 Jun 2009) | 11 lines
+
+Initial commit of an external serial flasher protocol.
+Supports RS-232, USB serial converters (untested) and TCP streams.
+
+All functionality is stubbed out to allow multiplatform compile testing
+of the headers we use.
+The real serial flasher protocol driver will be committed next.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r624 | stepan | 2009-06-23 12:44:36 +0200 (Tue, 23 Jun 2009) | 7 lines
+
+There are some non-C99 compilers out there used to compile flashrom.
+This fixes compilation for them.
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r623 | hailfinger | 2009-06-23 02:47:26 +0200 (Tue, 23 Jun 2009) | 7 lines
+
+SB600 SPI: Kill unused variable.
+
+Make a few local functions in sb600spi.c static.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r622 | hailfinger | 2009-06-22 13:14:43 +0200 (Mon, 22 Jun 2009) | 7 lines
+
+Mark MX25L6405 as PROBE supported.
+
+Thanks to Michael Stapelberg for the report.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r621 | hailfinger | 2009-06-22 13:07:44 +0200 (Mon, 22 Jun 2009) | 7 lines
+
+Mark the SST49LF003A as PROBE supported.
+
+Thanks to Simon Brown for the report.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r620 | hailfinger | 2009-06-22 12:09:07 +0200 (Mon, 22 Jun 2009) | 7 lines
+
+Mark ST M25P80 as completely supported.
+
+Thanks to Harald Gutmann for testing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r619 | hailfinger | 2009-06-22 12:06:28 +0200 (Mon, 22 Jun 2009) | 8 lines
+
+Eon EN25F40: Probe is tested.
+
+Thanks to Wangji for testing and pointing out that EN25* chips were
+unsupported, which was handled in r580 and r592.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r618 | uwe | 2009-06-22 03:37:06 +0200 (Mon, 22 Jun 2009) | 10 lines
+
+Turns out that the GIGABYTE GA-7ZM _does_ work fine if you disable
+the BIOS flash protection option _and_ remove jumper JP9 on the
+board (d'oh!).
+
+This board can decode 512 KB chips just fine (not just 256 KB).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r617 | uwe | 2009-06-21 22:50:22 +0200 (Sun, 21 Jun 2009) | 8 lines
+
+Add board-enable for Elitegroup K7VTA3 (trivial, tested on hardware).
+
+The board can decode 256 KB only (i.e., not 512 KB) it seems.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r616 | uwe | 2009-06-21 17:45:34 +0200 (Sun, 21 Jun 2009) | 13 lines
+
+Add board-enable code for the Shuttle AK38N.
+
+FYI, this board can only decode 256 KB chips (not 512 KB ones) unfortunately.
+The highest address line (A18) is not connected on this board.
+
+The it8705f_write_enable() is kept generic enough so it can be reused for other
+board-enables, possibly in the board_biostar_p4m80_m4() for example, but that
+shouldn't be touched for now, unless someone can test the code.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+
+------------------------------------------------------------------------
+r615 | uwe | 2009-06-20 03:21:38 +0200 (Sat, 20 Jun 2009) | 25 lines
+
+Various wiki output changes:
+
+ - Move board_info_url struct to print.c, doesn't have to be global.
+
+ - Simplify flashrom.c a bit by moving stuff to print.c.
+   Eliminate two now-useless mini-functions in print.c.
+
+ - Add a note that the wiki page contents are semi-automatically generated.
+
+ - Mention date of last wiki page update as well as the flashrom revision
+   that was used to generate the wiki output.
+
+ - Also generate list of supported laptops in -z output now.
+
+ - Add some more board URLs.
+
+ - Add a boards_notes[] table to allow for arbitrary footnotes/comments for
+   each board in the table. All notes will automatically be turned into
+   wiki footnotes with correct numbers and will appear at the end of the
+   respective table.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r614 | uwe | 2009-06-19 21:00:48 +0200 (Fri, 19 Jun 2009) | 21 lines
+
+Random bunch of wiki output and board status changes (trivial).
+
+ - Convert #defines for strings in print.c to 'const char *'s.
+
+ - Add missing entries in the board URL tables.
+
+ - Add a few more board URLs, partly contributed by 'Alien' at
+   http://www.coreboot.org/index.php?title=Flashrom&curid=1765&diff=8626&oldid=8625&rcid=3586
+
+ - Fix sort order of board lists.
+
+ - Add laptops to URL list (not yet used).
+
+ - Fix typo.
+
+ - Fix EPIA-EX15000/NX15000 names (append "G").
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r613 | uwe | 2009-06-19 17:54:39 +0200 (Fri, 19 Jun 2009) | 11 lines
+
+Add support for the AMD Am29F010A/B chips.
+
+Also, add support for the Silicon Image 3112(A) SATA controller.
+
+Both have been tested by Andrew Morgan <ziltro@ziltro.com> on hardware
+and work fine.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Andrew Morgan <ziltro@ziltro.com>
+
+
+------------------------------------------------------------------------
+r612 | uwe | 2009-06-19 16:22:16 +0200 (Fri, 19 Jun 2009) | 8 lines
+
+Mark VIA EPIA-EX15000 and VIA EPIA-NX15000 as working (trivial).
+
+Thanks Clark Rawlins <clark@bit63.org> for the report!
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r611 | hailfinger | 2009-06-19 16:20:34 +0200 (Fri, 19 Jun 2009) | 8 lines
+
+Prevent spurious runs of make features introduced by the FT2232 patch.
+The new makefile structure uses indirection (.features->features) to
+work around a gmake bug which resulted in immediate premature evaluation
+of variable definitions with deferred evaluation.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r610 | libv | 2009-06-19 15:53:59 +0200 (Fri, 19 Jun 2009) | 5 lines
+
+Board enable for EPIA-N(L).
+
+Signed-off-by: Jon Harrison <bothlyn@blueyonder.co.uk>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r609 | libv | 2009-06-19 15:00:24 +0200 (Fri, 19 Jun 2009) | 8 lines
+
+Board enable for Mitac 6513WU (Compaq OEM)
+
+ATX board for P3; Intel 82810e GMCHe, Intel 82801AA ICH and SMSC
+LPC47U332 super I/O.
+
+Signed-off-by: Michael Gold <mgold@ncf.ca>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r608 | hailfinger | 2009-06-19 13:23:57 +0200 (Fri, 19 Jun 2009) | 7 lines
+
+Kill obsolete exclude range feature. It is ignored by almost every chip
+and does not work for external flashers. Plus, it gives the user a false
+sense of security in some corner cases.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r607 | uwe | 2009-06-19 12:42:43 +0200 (Fri, 19 Jun 2009) | 16 lines
+
+Add a --list-supported-wiki / -z option which outputs the currently
+supported flash chips (and their status, size, and type), chipsets
+(plus status), mainboards (plus status), and external PCI devices
+usable as programmer to stdout.
+
+This allows for very easy pasting into the http://coreboot.org/Flashrom
+page, so we can keep that page up-to-date without much hassle.
+
+The list of boards is mostly new (known good ones which don't need
+write-enable code, and known-bad ones) and also lists URLs to the
+vendor's mainboard pages.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r606 | hailfinger | 2009-06-19 06:50:58 +0200 (Fri, 19 Jun 2009) | 6 lines
+
+Kill dead code which has been disabled since the very first commit of
+flashrom.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r605 | uwe | 2009-06-18 20:25:39 +0200 (Thu, 18 Jun 2009) | 22 lines
+
+Some more board status updates:
+
+Mark as OK:
+
+ - ASRock A770CrossFire (reported by RIVANVX on IRC, no email available).
+   User verified read and write with -wv, which VERIFIED OK.
+
+Mark as non-working for now:
+
+ - HP/Compaq nx9010 (laptop, reported by Murawski Mateusz <matowy@tlen.pl>).
+   Hangs upon 'flashrom -V' (needs hard power-cycle then).
+
+ - Elitegroup K7VTA3 (reported by Uwe Hermann <uwe@hermann-uwe.de>).
+   Needs board-enable.
+
+ - GIGABYTE GA-7ZM (reported by Uwe Hermann <uwe@hermann-uwe.de>).
+   Needs board-enable.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r604 | uwe | 2009-06-18 16:04:44 +0200 (Thu, 18 Jun 2009) | 8 lines
+
+Also print the supported/nonsupported laptops in -L output (trivial).
+
+Content taken from current wiki page.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r603 | hailfinger | 2009-06-18 14:42:46 +0200 (Thu, 18 Jun 2009) | 5 lines
+
+Chipset enable for VIA VT8233.
+
+Signed-off-by: Mateusz Murawski <matowy@tlen.pl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r602 | libv | 2009-06-17 16:43:24 +0200 (Wed, 17 Jun 2009) | 5 lines
+
+Board enable for Soyo SY-7VCA.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Andrew Morgan <ziltro@ziltro.com>
+
+------------------------------------------------------------------------
+r601 | uwe | 2009-06-17 14:07:12 +0200 (Wed, 17 Jun 2009) | 8 lines
+
+Move all printing code to print.c.
+
+Drop no longer needed MAX macro, we have a max() function.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r600 | hailfinger | 2009-06-17 12:13:42 +0200 (Wed, 17 Jun 2009) | 6 lines
+
+Use spi_nbyte_program in ichspi.c.
+This shortens the code a lot and makes it more readable.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r599 | uwe | 2009-06-17 01:15:10 +0200 (Wed, 17 Jun 2009) | 8 lines
+
+List the size (in KB) and type of supported flash chips in 'flashrom -L'.
+
+Also, list how many chips/chipsets/boards we support in 'flashrom -L'.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r598 | hailfinger | 2009-06-16 23:08:06 +0200 (Tue, 16 Jun 2009) | 21 lines
+
+This patch adds support for a new SPI programmer, based on the
+FT2232H/4232H chip from FTDI.
+
+FTDI support is autodetected during compilation.
+
+Paul writes:
+There are certainly possible improvements: The code has hard-coded
+values for which interface of the ftdi chip to use (interface B was
+chosen because libftdi seems to have trouble with A right now), what
+clock rate use for the SPI interface (I've been running at 30Mhz, but
+the patch sets it to 10Mhz), and possibly others. I think this means
+that per-programmer options might be a good idea at some point.
+
+Carl-Daniel writes:
+There is one additional FIXME comment in the code, but AFAICS that
+problem is not solvable with current libftdi.
+
+Signed-off-by: Paul Fox <pgf@laptop.org>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r597 | hailfinger | 2009-06-16 11:31:51 +0200 (Tue, 16 Jun 2009) | 5 lines
+
+Check for a working C compiler.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Joseph Smith <joe@settoplinux.org>
+
+------------------------------------------------------------------------
+r596 | hailfinger | 2009-06-16 10:55:44 +0200 (Tue, 16 Jun 2009) | 10 lines
+
+This patch gives us arbitrary range reads at byte boundaries for every
+single chip supported by flashrom.
+That means you can tell flashrom to read exactly bytes 12345-56789
+(start 12345, length 44445) and it will not fetch a single byte more.
+
+Uwe tested this on one LPC, one SPI, and one parallel flash board.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r595 | hailfinger | 2009-06-15 19:23:36 +0200 (Mon, 15 Jun 2009) | 16 lines
+
+flashrom only checks for very few chips if the erase worked.
+And even when it checks if the erase worked, the result of that check is
+often ignored.
+
+Convert all erase functions and actually check return codes
+almost everywhere.
+Check inside all erase_* routines if erase worked, not outside.
+erase_sector_jedec and erase_block_jedec have changed prototypes to
+enable erase checking.
+
+Uwe successfully tested LPC on an CK804 box and SPI on some SB600 box.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r594 | hailfinger | 2009-06-15 16:14:48 +0200 (Mon, 15 Jun 2009) | 10 lines
+
+flash.h not only contains function prototypes and general settings, it
+also has a huge chunk of chip and vendor IDs in the middle.
+
+Split them out into a separate flashchips.h and adjust
+#include wherever needed.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r593 | uwe | 2009-06-15 15:27:49 +0200 (Mon, 15 Jun 2009) | 11 lines
+
+Fix typo in Makefile (trivial).
+
+This strangely breaks with gmake on FreeBSD, but seems to work with make
+on Linux.
+
+Thanks Idwer Vollering <vidwer@gmail.com> for noticing and testing.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r592 | hailfinger | 2009-06-15 14:10:57 +0200 (Mon, 15 Jun 2009) | 12 lines
+
+Fix the vendor ID of
+EN25B05, EN25B10, EN25B20, EN25B40, EN25B80, EN25B16, EN25B32, EN25B64
+EN25F40, EN25F80, EN25F16
+
+Add support for
+EN25P05, EN25P10, EN25P20, EN25P40, EN25P80, EN25P16, EN25P32, EN25P64
+EN25D16
+EN25F05, EN25F10, EN25F20, EN25F32
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r591 | uwe | 2009-06-15 02:03:37 +0200 (Mon, 15 Jun 2009) | 8 lines
+
+The VIA VX800 chipset works with the VT8237S code after adding an
+entry for the VX800 PCI ID.
+
+Signed-off-by: Arjan Koers <0h3q2rmn2bdb@list.nospam.xutrox.com>
+Acked-by: Bari Ari <bari@onelabs.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r590 | uwe | 2009-06-14 23:53:26 +0200 (Sun, 14 Jun 2009) | 9 lines
+
+Add support for the PMC Pm29F002T/B chips.
+
+I sucessfully tested all operations on a Pm29F002T chip. The Pm29F002B is
+untested but I assume it should also work.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r589 | hailfinger | 2009-06-13 14:04:03 +0200 (Sat, 13 Jun 2009) | 19 lines
+
+Every SPI host controller implemented its own way to read flash chips.
+This was partly due to a design problem in the abstraction layer.
+
+There should be exactly two different functions for reading SPI chips:
+- memory mapped reads
+- SPI command reads.
+
+Each of them should be contained in a separate function, optionally
+taking parameters where needed.
+
+This patch solves the problems mentioned above, shortens the code and
+makes the code logic a lot more obvious.
+
+Since open-coding the min() function leads to errors, include it in this
+patch as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r588 | hailfinger | 2009-06-12 23:29:36 +0200 (Fri, 12 Jun 2009) | 5 lines
+
+Add bus type and timing info for some flash chips.
+
+Signed-off-by: Mateusz Murawski <matowy@tlen.pl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r587 | hailfinger | 2009-06-12 16:49:10 +0200 (Fri, 12 Jun 2009) | 31 lines
+
+This patch introduces two new targets which are designed to make the
+life of packagers easier.
+In particular, it should no longer be necessary to patch the makefile
+for hassle-free compilation.
+
+The targets are:
+make export
+make tarball
+Both preserve svn revisions and the exported tree does not depend on
+subversion in any way or shape.
+
+Documentation for this feature has been added to README.
+
+We need this for five reasons:
+1. Packagers currently have to patch flashrom source to compile it on
+systems without subversion. We should make it easier for them.
+2. Snapshot tarballs currently have a .svn 1.5 directory included but
+this will cause errors for users with older svn 1.4. Not requiring
+subversion for snapshot compilation is best.
+3. Since packagers seldom the svn revision in their fixup patches, some
+packages out there have incorrect or no revision, only major version
+numbers.
+4. Releasing a new version of flashrom needs too many changes to the
+makefile which have to be reverted instantly after the release. That is
+unnecessary churn.
+5. Making a release is easy with the change. Update the major version,
+then run "make tarball".
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>  
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r586 | uwe | 2009-06-12 16:05:25 +0200 (Fri, 12 Jun 2009) | 7 lines
+
+Add missing GPL headers to two files. Please complain in case there are
+errors here, but I'm pretty sure the headers are correct.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r585 | hailfinger | 2009-06-12 16:02:07 +0200 (Fri, 12 Jun 2009) | 10 lines
+
+flashrom does not honor argument ordering for operations. Not only does
+this violate the principle of least surprise, it also caused one bug
+where -Ewv was specified and the flash ended up being empty.
+
+Support only one operation at a time.
+As a side benefit, this allows us to clean up main() quite a bit.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r584 | hailfinger | 2009-06-12 13:45:10 +0200 (Fri, 12 Jun 2009) | 6 lines
+
+Add #defines for some flash chips.
+Add timing info to some flash chips.
+
+Signed-off-by: Mateusz Murawski <matowy@tlen.pl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r583 | hailfinger | 2009-06-12 10:10:33 +0200 (Fri, 12 Jun 2009) | 5 lines
+
+Add spi_nbyte_program as generic function to the SPI layer.
+
+Signed-off-by: Paul Fox <pgf@laptop.org>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r582 | hailfinger | 2009-06-12 10:04:08 +0200 (Fri, 12 Jun 2009) | 5 lines
+
+Tell the user about the beginning and end of the write operation.
+
+Signed-off-by: Paul Fox <pgf@laptop.org>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r581 | libv | 2009-06-09 20:29:30 +0200 (Tue, 09 Jun 2009) | 13 lines
+
+Add board enable for Albatron PM266A boards.
+
+There are multiple albatron pm266a boards which all share the same bios
+image. This means that both the board enable and the subsystem ids are
+exactly the same.
+
+The board enable is the same as the epox EP-8K5A2, namely only raising
+memw on the superio.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+Acked-by: Mateusz Murawski <matowy@tlen.pl>
+
+------------------------------------------------------------------------
+r580 | hailfinger | 2009-06-05 22:53:07 +0200 (Fri, 05 Jun 2009) | 18 lines
+
+Add all Eon EN25* SPI chips. Some IDs were already in flash.h.
+EN25B05
+EN25B10
+EN25B20
+EN25B40
+EN25B80
+EN25B16
+EN25B32
+EN25B64
+EN25F40
+EN25F80
+EN25F16
+
+EN25P* are supported as well, but they seem to be identical to EN25B.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r579 | hailfinger | 2009-06-05 20:32:07 +0200 (Fri, 05 Jun 2009) | 18 lines
+
+Sometimes we want to read/write more than 4 bytes of chip content at
+once.
+Add chip_{read,write}n to the external flasher infrastructure which
+read/write n bytes at once.
+
+Fix a few places where the code used memcpy/memcmp although that is
+strictly impossible with external flashers.
+Place a FIXME in the layout.c code because usage is not totally clear
+and needs to be fixed to support external flashers.
+
+As a nice side benefit, we get a noticeable speedup for builtin flash
+reading which is now a memcpy() of the full flash area instead of a
+series of single-byte reads.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r578 | hailfinger | 2009-06-05 19:48:08 +0200 (Fri, 05 Jun 2009) | 7 lines
+
+Add external programmer delay functions so external programmers can
+handle the delay on their own if needed.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Urja Rannikko <urjaman@gmail.com>
+
+------------------------------------------------------------------------
+r577 | hailfinger | 2009-06-05 19:04:37 +0200 (Fri, 05 Jun 2009) | 6 lines
+
+Fix a bug in dummyflasher.c special case where no type parameter is
+given.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r576 | hailfinger | 2009-06-05 15:46:17 +0200 (Fri, 05 Jun 2009) | 5 lines
+
+Add probe timings forgotten in r569.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Paul Menzel <paulepanter@users.sourceforge.net>
+
+------------------------------------------------------------------------
+r575 | hailfinger | 2009-06-05 15:30:49 +0200 (Fri, 05 Jun 2009) | 6 lines
+
+Use flash->virtual_registers for what they were meant for instead of
+recalculating them every time.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r574 | hailfinger | 2009-06-05 10:47:37 +0200 (Fri, 05 Jun 2009) | 9 lines
+
+Exact bustypes for Atmel AT29C010A, AT29C020, AT29C040A, AT49BV512,
+AT49F002, AMIC A29040B, A49LF040A,
+EMST F49B002UA, EON EN29F002, Intel 28F001BX-B, 28F001BX-T, Winbond
+W29C020C and W29C040P.
+Checked from datasheets. A49LF040A is LPC, others parallel.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r573 | uwe | 2009-06-05 02:42:18 +0200 (Fri, 05 Jun 2009) | 7 lines
+
+Actually enable the protection register debug output on
+SST49LF160C and similar chips if -V is supplied.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Myles Watson<mylesgw@gmail.com>
+
+
+------------------------------------------------------------------------
+r572 | uwe | 2009-06-04 21:25:54 +0200 (Thu, 04 Jun 2009) | 7 lines
+
+Let's actually sort the board lists alphabetically, and not just pretend
+we do (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r571 | uwe | 2009-06-04 20:53:03 +0200 (Thu, 04 Jun 2009) | 10 lines
+
+Mark the ASUS A7N8X-E Deluxe as working.
+
+I finally found the machine (doesn't belong to me) where I originally tested
+this board as non-working and I can confirm that all operations work fine now
+(since the nForce2 patch in r548).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r570 | hailfinger | 2009-06-03 18:41:11 +0200 (Wed, 03 Jun 2009) | 6 lines
+
+Use macros for inb and outb which were forgotten in r568.
+This makes FreeBSD happy.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r569 | hailfinger | 2009-06-03 16:46:22 +0200 (Wed, 03 Jun 2009) | 7 lines
+
+Add probe_timing information (int uS value). This eliminates the
+conflicting delay requirements for old and new chips with the same
+probing sequence.
+
+Signed-Off-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r568 | libv | 2009-06-03 09:50:39 +0200 (Wed, 03 Jun 2009) | 9 lines
+
+Board enable: Gigabyte GA K8N SLI.
+
+Raises bits 0 and 2 on offset 0xE1 in the system control area of the
+nvidia ck804 lpc.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
+
+------------------------------------------------------------------------
+r567 | uwe | 2009-06-02 21:54:22 +0200 (Tue, 02 Jun 2009) | 7 lines
+
+Mark the 10b7:9058 3COM card (3C905B: Cyclone 10/100/BNC) as "OK", forgot
+this in the last commit. Also do some random cleanups while I'm at it.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r566 | uwe | 2009-06-02 18:45:59 +0200 (Tue, 02 Jun 2009) | 9 lines
+
+Add support for the 10b7:9058 3COM NIC (3C905B: Cyclone 10/100/BNC).
+Also, add Atmel AT29C512 support.
+
+Both are tested on hardware by Maciej Pijanka.
+
+Signed-off-by: Maciej Pijanka <maciej.pijanka@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r565 | uwe | 2009-06-02 15:39:42 +0200 (Tue, 02 Jun 2009) | 10 lines
+
+Add two more boards supported by flashrom:
+
+ - ASUS A8N-SLI (reported by Ryan McLean <pvtryan100@googlemail.com>)
+
+ - MSI/Medion MS-7255 (P4M890M) (reported by J?\195?\182rg Schirottke <master@kanotix.com>)
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r564 | hailfinger | 2009-06-02 02:38:14 +0200 (Tue, 02 Jun 2009) | 5 lines
+
+Unify AMD manufacture_id and model_id
+
+Signed-off-by: Mateusz Murawski <matowy@tlen.pl>
+Acked-by: FENG Yu Ning <fengyuning1984@gmail.com>
+
+------------------------------------------------------------------------
+r563 | hailfinger | 2009-06-02 00:07:52 +0200 (Tue, 02 Jun 2009) | 5 lines
+
+Use read_flash() when flash chip probe is forced.
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r562 | hailfinger | 2009-06-01 23:37:00 +0200 (Mon, 01 Jun 2009) | 5 lines
+
+Add a missing free() in read_flash().
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r561 | hailfinger | 2009-06-01 23:30:42 +0200 (Mon, 01 Jun 2009) | 7 lines
+
+Refactor HT-1000 GPIO setting to use sio_mask. Although the HT-1000
+GPIOs are not SuperIO related, the share the same index/data register
+access method.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r560 | hailfinger | 2009-06-01 04:08:58 +0200 (Mon, 01 Jun 2009) | 15 lines
+
+Only probe for chips with compatible bus protocols.
+It doesn't make sense to probe for SPI chips on a LPC host, nor does it
+make sense to probe for LPC chips on a Parallel host.
+
+This change is backwards compatible, but adding host protocol info to
+chipset init functions will speed up probing.
+
+Once all chipset init functions are updated and the Winbond W29EE011 and
+AMIC A49LF040A chip definitions are updated, the W29EE011 workaround can
+be deleted as the W29/A49 conflict magically disappears.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested on real hardware and
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r559 | hailfinger | 2009-06-01 02:02:11 +0200 (Mon, 01 Jun 2009) | 13 lines
+
+Add bus type support to the dummy external programmer.
+
+The syntax is explained in the man page.
+Example: flashrom -p dummy=lpc,fwh
+
+Tested, works perfectly. ;-)
+
+As a nice benefit, it allows easy testing of the "probe only compatible
+flashes" patch.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r558 | uwe | 2009-05-31 23:35:10 +0200 (Sun, 31 May 2009) | 6 lines
+
+Fix warning in satasii.c when compiling with gcc 4.4.0.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r557 | hailfinger | 2009-05-31 20:00:57 +0200 (Sun, 31 May 2009) | 7 lines
+
+Add IT87xx SPI as external flasher option.
+This is a fast way to test if a IT87xx board_enable() would work.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Harald Gutmann <harald.gutmann@gmx.net>
+Acked-by: Harald Gutmann <harald.gutmann@gmx.net>
+
+------------------------------------------------------------------------
+r556 | hailfinger | 2009-05-31 19:57:34 +0200 (Sun, 31 May 2009) | 16 lines
+
+Add bus type annotation to struct flashchips. Right now, the annotation
+only differentiates between SPI and non-SPI. Anyone who knows more about
+a specific flash chip should feel free to update it.
+
+The existing flashbus variable was abused to denote the SPI controller
+type. Use an aptly named variable for that purpose.
+
+Once this patch is merged, the chipset/programmer init functions can set
+supported flash chip types and flashrom can automatically select only
+matching probe/read/erase/write functions.
+A side benefit of that will be the elimination of the Winbond W29EE011
+vs. AMIC A49LF040A conflict.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r555 | hailfinger | 2009-05-29 14:55:31 +0200 (Fri, 29 May 2009) | 9 lines
+
+Add support for probe and read of Intel 28F001BX-T and BX-B.
+
+Erase & write support wont be this easy - the chips need 12V Vpp
+(needs a hardware hack or a supporting mb) and they have a very weird
+layout and are old.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r554 | uwe | 2009-05-28 17:07:42 +0200 (Thu, 28 May 2009) | 19 lines
+
+Random flashrom updates:
+
+ - Add explicit installation instructions in the README.
+
+ - Code cleanups, coding style fixes, drop dead code.
+
+ - Drop duplicate board listings from -L output (some boards were explicitly
+   recorded in boards_ok[] _and_ implicitly via the board-enables table.
+
+ - Add MS-xxxx numbers to MSI boards where we can find that info.
+
+ - Fix typo, "K8T Neo2" should have been "K8T Neo2-F" actually, at least
+   according to the comment of w83627thf_gpio4_4_raise_2e() which says
+   "Suited for: MSI K8T Neo2-F".
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r553 | uwe | 2009-05-28 02:00:23 +0200 (Thu, 28 May 2009) | 40 lines
+
+A bunch of flashrom board updates:
+
+Marked as OK:
+
+ - ASUS M2V (reported by Henri Valta <henri.valta@kemi.fi>)
+   http://www.coreboot.org/pipermail/coreboot/2009-May/048674.html
+
+ - Jetway J7F4K1G5D-PB (reported by Kevin O'Connor <kevin@koconnor.net>)
+
+ - PC Engines Alix.3d3 (reported by Tobias M?\195?\188ller <Tobias_Mueller@twam.info>)
+   http://www.coreboot.org/pipermail/coreboot/2009-May/048549.html
+
+ - MSI K7N2 (reported by Maciej Pijanka <maciej.pijanka@gmail.com>)
+   http://www.coreboot.org/pipermail/coreboot/2009-May/048777.html
+
+Marked as (so far) non-working:
+
+ - DFI 855GME-MGF (reported by Tobias M?\195?\188ller <Tobias_Mueller@twam.info>)
+   http://www.coreboot.org/pipermail/coreboot/2009-May/048549.html
+
+ - ASUS M3N78 Pro (reported by Piotr Esden-Tempski <esden@esden.net>)
+   As discussed on IRC this is an MCP78 chipset with SPI translation apparently
+   done in the southbridge, and we have no NVIDIA datasheets, of course. So the
+   situation for this board will probably not change anytime soon.
+
+ - MSI MS-6178 (reported by Uwe Hermann <uwe@hermann-uwe.de>)
+   I tested write/erase will not work on this board, so a write-enable is
+   needed. In _addition_, the board immediately powers off if you hot-unplug
+   the PLCC chip, so I guess there's some SMI interference.
+
+ - GIGABYTE GA-K8N-SLI (reported by Alexander Gordeev <lasaine@lvk.cs.msu.su>)
+   This is currently being discussed on the mailing list (see
+   http://www.coreboot.org/pipermail/coreboot/2009-May/048717.html) and it's
+   very likely that we'll be able to add a board-enable, so this board can be
+   maked as OK soonish.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r552 | uwe | 2009-05-28 01:17:40 +0200 (Thu, 28 May 2009) | 9 lines
+
+Change 'Texas Instruments' to 'TI' in the flash chip table, as this is
+a very long name and currently even breaks -L output. We could of course
+fix that, but we already use short / abbreviated names for other vendors
+(AMD, ST, SST, PMC) so do it for TI also.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r551 | hailfinger | 2009-05-27 13:40:08 +0200 (Wed, 27 May 2009) | 9 lines
+
+Use consistent naming for local chip ID variables. Every chip besides
+SPI and w39v080fa uses id1/id2 as local variable names to store ID
+responses from the flash chip.
+This eases grepping a lot. As a bonus, it also frees up some names to be
+used as parameters.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
+
+------------------------------------------------------------------------
+r550 | hailfinger | 2009-05-26 23:26:23 +0200 (Tue, 26 May 2009) | 5 lines
+
+Add TI TMS29F002RT and TMS29F002RB probe and read support to flashrom.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r549 | hailfinger | 2009-05-26 23:25:08 +0200 (Tue, 26 May 2009) | 28 lines
+
+Use REMS instead of RES in the ICH SPI default opcode table.
+
+RES is Read Electronic Signature (1 Byte, identical for different chips)
+REMS is Read Electronic Manufacturer Signature (2 Bytes, mostly unique)
+RDID is Read JEDEC ID (3 bytes, unique)
+
+Of the chips which don't support RDID, a sizable portion supports REMS
+which gives us both a manufacturer ID and a device ID. This is clearly
+superior to having only a device ID (the RES case) which has multiple
+documented collisions.
+
+The RES/REMS problem is aggravated by inconsistent naming in vendor data
+sheets. What's in a name? Considering that we have 1-byte IDs, 2-byte
+IDs and 3+byte IDs with varying names but mostly consistent opcodes, it
+makes sense to set our own standard about how the opcodes are called.
+
+The best way forward would be to have the ICH SPI driver reprogram the
+opcode menu on the fly if the opcode menu doesn't contain the requested
+opcode and the opcode menu is not locked. Until that happens, this patch
+improves detection accuracy by a factor of 256 for some chips.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Tested-by: Uwe Hermann
+with the flash chip "SST SST25VF040.REMS".
+
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r548 | libv | 2009-05-26 11:48:28 +0200 (Tue, 26 May 2009) | 11 lines
+
+Add NForce2 chipset enable.
+
+While the other chipset enables for nvidia could potentially also work,
+this one, by not touching other bits, seems like the safest solution.
+
+Uwe tested this on his Asus A7N8X Deluxe, so hopefully the A7N8X-E
+(reporter unknown) is now no longer an issue.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r547 | hailfinger | 2009-05-26 01:26:50 +0200 (Tue, 26 May 2009) | 12 lines
+
+Refactor SuperIO accesses. We had duplicated code under different names
+and even open-coded some functions in some places.
+
+wbsio_read/regval -> sio_read
+wbsio_write/regwrite -> sio_write
+wbsio_mask -> sio_mask
+
+board_biostar_p4m80_m4 now uses existing IT87 functions.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+
+------------------------------------------------------------------------
+r546 | libv | 2009-05-25 13:35:25 +0200 (Mon, 25 May 2009) | 7 lines
+
+Biostar p4m80 board enable typo.
+
+Obvious typo due to inb/outb versus wbsio_ argument ordering confusion.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r545 | uwe | 2009-05-23 02:56:49 +0200 (Sat, 23 May 2009) | 10 lines
+
+Autodetection support and write-enable for the MSI KT4 Ultra.
+
+Thanks Christian Ruppert <spooky85@gmail.com> for testing on hardware.
+
+(also: Fix a typo and some whitespace while I'm at it)
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r544 | uwe | 2009-05-22 15:18:38 +0200 (Fri, 22 May 2009) | 6 lines
+
+Add website section (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r543 | oxygene | 2009-05-22 13:37:27 +0200 (Fri, 22 May 2009) | 22 lines
+
+A bunch of output beautifications and improvements, as well as doc
+fixes:
+
+ - Update manpage, we now report supported boards via -L.
+ - Add some missing escaping for '-' characters in the manpage.
+
+ - Shorten some of the really long device names, so that -L output looks
+   nicer.
+   
+ - Display a "table header" for all entries/columns in -L output.
+ - Make -L output tabular for all lists for better readability.
+ - Do not print "unknown XXXX SPI chip" entries in -L output.
+ - And random other cosmetics...
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
+
+------------------------------------------------------------------------
+r542 | uwe | 2009-05-21 19:11:25 +0200 (Thu, 21 May 2009) | 23 lines
+
+Mark the following boards as 'known-good' (write/erase works):
+
+ - ASUS P5B-Deluxe (reported by Andrew Paprocki)
+ - ASUS P6T Deluxe V2 (reported by Aldrik Dunbar)
+ - GIGABYTE GA-6ZMA (reported by Urja Rannikko)
+ - Intel EP80759 (reported by Stephan GUILLOUX)
+ - MSI MS-7345 (P35 Neo2-FIR) (reported by Onno)
+ - MSI MS-7168 (Orion) (reported by ubuntosaure)
+ - Supermicro H8QC8 (reported by Victor Zele)
+Mark the following boards as 'known-bad' (they likely require a write-enable):
+
+ - Abit IS-10 (reported by deejkuba)
+ - ASUS P5B (reported by Henning Fleddermann)
+ - ASUS P5BV-M (reported by Bernhard M. Wiedemann)
+ - Boser HS-6637 (reported by Mark Robinson)
+Also, mark the Winbond W39V040A as fully tested (report by ubuntosaure).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r541 | uwe | 2009-05-21 17:59:58 +0200 (Thu, 21 May 2009) | 8 lines
+
+Make an extra MANDIR variable for easier overriding (trivial).
+
+Thanks Heinz Wiesinger <HMWiesinger@liwjatan.at> for the report.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r540 | uwe | 2009-05-21 17:55:46 +0200 (Thu, 21 May 2009) | 11 lines
+
+Improve flashrom test report text a bit:
+
+ - Mention that we'd like to have -V output for all operations
+   which were tested by the user.
+
+ - Mention that we'd like to know the exact mainboard vendor/name.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r539 | uwe | 2009-05-21 02:29:50 +0200 (Thu, 21 May 2009) | 6 lines
+
+Fix typo (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r538 | uwe | 2009-05-21 01:27:16 +0200 (Thu, 21 May 2009) | 8 lines
+
+Mark the Macronix MX29F002T as working (trivial).
+
+I tested all operations on hardware.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r537 | uwe | 2009-05-20 19:09:43 +0200 (Wed, 20 May 2009) | 6 lines
+
+The Silicon Image PCI0680 has bit 26 marked as reserved, so don't use it.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r536 | uwe | 2009-05-19 23:03:31 +0200 (Tue, 19 May 2009) | 22 lines
+
+Mark the Silicon Image PCI0680 Ultra ATA-133 controller as working.
+
+I tested identify, read, write, erase, verify successfully, HOWEVER,
+this will only work (at least on my card) after de-soldering the
+soldered-on PLCC32 one-time programmable (OTP) chip (Holtek HT27C010)
+and soldering on a (re-)programmable flash ROM chip or a socket.
+
+Example:
+
+http://www.coreboot.org/File:Sii_controller1.jpg
+http://www.coreboot.org/File:Sii_controller2.jpg
+
+The OTP chip which came on my card does not react to the standard JEDEC
+identify/read/write/erase commands anymore, so if all other such PCI0680
+controllers which are around also have the same OTP chip (that's not
+necessarily the case), they cannot be used as "external programmer" in
+flashrom without the above mentioned modifications.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r535 | uwe | 2009-05-19 16:14:21 +0200 (Tue, 19 May 2009) | 6 lines
+
+Documentation improvements and small code/whitespace fixes (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r534 | uwe | 2009-05-19 00:27:53 +0200 (Tue, 19 May 2009) | 13 lines
+
+Add detection support and write-enable for the GIGABYTE GA-MA78GM-S2H.
+Thanks Michael Heimann for reporting.
+
+The board was misidentified as a GIGABYTE GA-MA78G-DS3H though, as the
+old PCI IDs and subsystem IDs of match. Thus, use differing ones for
+both boards, which is not so easy. The only usable-looking difference
+is in the SATA controller subsystem IDs. This should allow us to
+properly detect both boards.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r533 | uwe | 2009-05-18 23:56:16 +0200 (Mon, 18 May 2009) | 6 lines
+
+Drop duplicate Tyan S2498 (Tomcat K7M) entry in the board list (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r532 | uwe | 2009-05-18 17:31:10 +0200 (Mon, 18 May 2009) | 7 lines
+
+Add Tyan S2891/S2892/S2895 as supported without special write-enables
+being required. Thanks Myles Watson <mylesgw@gmail.com> for the report.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r531 | uwe | 2009-05-18 01:12:17 +0200 (Mon, 18 May 2009) | 7 lines
+
+Factor out fallback_map/unmap, most external programmers don't need
+and special handling here (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r530 | uwe | 2009-05-18 00:58:41 +0200 (Mon, 18 May 2009) | 6 lines
+
+Rename sata_sii.c to satasii.c for consistency (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r529 | uwe | 2009-05-18 00:57:34 +0200 (Mon, 18 May 2009) | 17 lines
+
+Various smaller flashrom improvements:
+
+ - Document new 'satasii' programmer in -L output and manpage.
+
+ - Drop PCI_IO_BASE_ADDRESS, pci.h has such #defines already.
+
+ - Beautify flashrom output and make it more consistent.
+ - Same for the 'make' output (reordered some $CC parameters).
+   Build-tested on i386, shouldn't break any builds, I think.
+
+ - Some variable renaming and other cosmetic fixes.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r528 | ruik | 2009-05-17 21:46:43 +0200 (Sun, 17 May 2009) | 12 lines
+
+This patch adds support for BIOS flashing on the all SiliconImage SATA
+controllers. It was easy because
+
+1) flashrom has now nice API
+2) documentation is public on the web site
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+Don't forget to add a files. Because I do.
+
+
+------------------------------------------------------------------------
+r527 | ruik | 2009-05-17 21:39:27 +0200 (Sun, 17 May 2009) | 10 lines
+
+This patch adds support for BIOS flashing on the all SiliconImage SATA
+controllers. It was easy because
+
+1) flashrom has now nice API
+2) documentation is public on the web site
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r526 | ruik | 2009-05-17 20:24:24 +0200 (Sun, 17 May 2009) | 5 lines
+
+Fix a quilt introduced bug in patch.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Self-acked-by: Rudolf Marek <r.marek@assembler.cz>
+
+------------------------------------------------------------------------
+r525 | ruik | 2009-05-17 19:02:07 +0200 (Sun, 17 May 2009) | 16 lines
+
+[PATCH] flashrom add PMC 39F010
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+[PATCH] tested SST39VF010
+
+Self-ack is fine for test reports.
+
+Rudolf Marek wrote:
+> > Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r524 | hailfinger | 2009-05-17 17:49:24 +0200 (Sun, 17 May 2009) | 56 lines
+
+Use accessor functions for MMIO. Some MMIO accesses used volatile,
+others didn't (and risked non-execution of side effects) and even with
+volatile, some accesses looked dubious.
+
+Since the MMIO accessor functions and the onboard flash accessor
+functions are functionally identical (but have different signatures),
+make the flash accessors wrappers for the MMIO accessors.
+
+For some of the conversions, I used Coccinelle. Semantic patch follows:
+
+@@
+typedef uint8_t;
+expression a;
+volatile uint8_t *b;
+@@
+- b[a]
++ *(b + a)
+@@
+expression a;
+volatile uint8_t *b;
+@@
+- *(b) |= (a);
++ *(b) = *(b) | (a);
+@@
+expression a;
+volatile uint8_t *b;
+@@
+- *(b) = (a);
++ mmio_writeb(a, b);
+@@
+volatile uint8_t *b;
+@@
+- *(b)
++ mmio_readb(b)
+@@
+type T;
+T b;
+@@
+(
+ mmio_readb
+|
+ mmio_writeb
+)
+ (...,
+- (T)
+- (b)
++ b
+ )
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Uwe tested read, write, erase with this patch on a random board to make
+sure nothing breaks.
+
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r523 | uwe | 2009-05-17 01:42:17 +0200 (Sun, 17 May 2009) | 13 lines
+
+List all boards which are:
+
+ - Supported out of the box (no flash enables required)
+
+ - Verifiably not yet working (unknown flash enable)
+
+Also, move some structs to flash.h in preparation for later wiki
+output support.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r522 | uwe | 2009-05-17 00:36:00 +0200 (Sun, 17 May 2009) | 9 lines
+
+Eliminate all 'inline's from the flashrom code. They serve pretty
+much no purpose, compilers can optimize pretty much all of what we
+might mark as inline anyway, _and_ inlines are not enforced in any
+way by the compiler either. They're totally unneeded. Kill them.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r521 | uwe | 2009-05-17 00:05:42 +0200 (Sun, 17 May 2009) | 8 lines
+
+Drop unused/duplicated #includes and some dead code (trivial).
+
+Build-tested on 32bit x86.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r520 | uwe | 2009-05-16 23:39:19 +0200 (Sat, 16 May 2009) | 12 lines
+
+Add proper workaround for 3COM 3C90xB cards, which need special fixups
+(the 3C90xC ones don't). This is tested on hardware.
+
+Also, add initial support for the Atmel AT29C010A chip (which I inserted
+in a 3COM 3C90xB card for testing). It can be detected, read works, erase
+works, but write will need some additional code (will post in another
+patch later).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r519 | hailfinger | 2009-05-16 23:22:56 +0200 (Sat, 16 May 2009) | 17 lines
+
+Use chipaddr instead of volatile uint8_t * because when we access
+chips in external flashers, they are not accessed via pointers at all.
+
+Benefits:
+This allows us to differentiate between volatile machine memory accesses
+and flash chip accesses.
+It also enforces usage of chip_{read,write}[bwl] to access flash chips,
+so nobody will unintentionally use pointers to access chips anymore.
+Some unneeded casts are removed as well.
+Grepping for chip operations and machine memory operations doesn't yield
+any false positives anymore.
+
+Compile tested on 32 bit and 64 bit Linux.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r518 | uwe | 2009-05-16 03:30:48 +0200 (Sat, 16 May 2009) | 11 lines
+
+Older libpci versions (e.g. 2.2.8, as it's default on current FreeBSD 7.2)
+don't properly fill the base_addr[0] struct member, so revert back to
+an explicit pci_read_long() call, otherwise detection of PCI devices and
+their base address will fail with strange error messages.
+
+Thanks Idwer Vollering <vidwer@gmail.com> for reporting and testing.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r517 | hailfinger | 2009-05-16 03:23:55 +0200 (Sat, 16 May 2009) | 9 lines
+
+Add generic 16 bit and 32 bit chip read/write emulation to the external
+flasher infrastructure. The emulation works by splitting 32 bit accesses
+into 16 bit accesses and 16 bit accesses into to 8 bit accesses.
+That way, external flashers can mix and match the amount of emulation
+they need.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r516 | hailfinger | 2009-05-16 01:36:23 +0200 (Sat, 16 May 2009) | 9 lines
+
+Uwe tested the recent SB600 SPI commit and notified me of one unexpected
+problem. It seems some boards do not use SPI_HOLD at all. Take that into
+account when trying to figure out if SPI is available.
+
+Print the SB600 ROM strap override register status for better debugging.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r515 | uwe | 2009-05-15 19:02:34 +0200 (Fri, 15 May 2009) | 14 lines
+
+Refactor parts of the 3COM NIC code.
+
+Move the reusable PCI specific parts into pcidev.c, they'll be usable
+for other NIC code (Realtek, VIA, ...) and also for SATA/IDE controller
+cards as external programmers (for every PCI device which can program
+EEPROMs basically).
+
+Also add print_supported_pcidevs() to show the supported PCI devices
+(currently only NICs, soon more) in the 'flashrom -L' output.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r514 | hailfinger | 2009-05-15 02:56:22 +0200 (Fri, 15 May 2009) | 17 lines
+
+Until the ICH SPI driver can handle preopcodes as standalone opcodes, we
+should handle such special opcode failure gracefully on ICH and
+compatible chipsets.
+
+This fixes status register writes on almost all ICH+VIA SPI masters.
+
+The fix is almost identical to r484, but this time it affects the EWSR
+(Enable Write Status Register) opcode instead of the WREN (Write Enable)
+opcode.
+
+With the differentiated return codes introduced in r500, the workaround
+is more precise this time. The old WREN workaround was updated as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: FENG Yu Ning <fengyuning1984@gmail.com>
+Acked-by: Cristi Magherusan <cristi.magherusan@net.utcluj.ro>
+
+------------------------------------------------------------------------
+r513 | uwe | 2009-05-15 00:58:21 +0200 (Fri, 15 May 2009) | 40 lines
+
+Make the nic3com code check how many supported NICs are found. If we find
+multiple ones, abort with a message to the user, suggesting to use the
+
+  flashrom -p nic3com=bb:dd.f
+
+syntax. If exactly one supported NIC is found, use it. If none is found,
+abort with an error.
+
+Print the bb:dd.f numbers for all supported NICs we find, so the user
+doesn't have to poke around in lspci output to find the desired bb:dd.f.
+
+Also, drop one pci_read_long() in favor of using the already existing
+base_addr[0] struct field.
+
+Drop the BAR in user messages, it's not really useful for us. Instead,
+explain the BDF syntax a bit more verbosely.
+
+While I'm at it, update the manpage some more to mention and fully document
+the external programmer support we have (or will have soon).
+
+The patch is tested on hardware:
+
+$ flashrom -p nic3com
+flashrom v0.9.0-r512
+Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200, BDF 05:04.0)
+Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200, BDF 05:03.0)
+Error: Multiple supported NICs found. Please use 'flashrom -p nic3com=bb:dd.f'
+to explicitly select the card with the given BDF (PCI bus, device, function).
+
+$ flashrom -p nic3com=05:04.0
+flashrom v0.9.0-r512
+Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200, BDF 05:04.0)
+Calibrating delay loop... OK.
+Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000.
+No operations were specified.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r512 | hailfinger | 2009-05-14 23:41:10 +0200 (Thu, 14 May 2009) | 5 lines
+
+Fix compilation of nic3com on 64bit.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r511 | uwe | 2009-05-14 22:41:57 +0200 (Thu, 14 May 2009) | 7 lines
+
+Factor out portable iopl()-style code into a global function
+which all programmers can use, add missing close() call (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r510 | uwe | 2009-05-14 20:57:26 +0200 (Thu, 14 May 2009) | 9 lines
+
+3COM: Add support for users to specify a certain NIC via PCI bus:slot.func
+notation, in case there are multiple NICs in one system.
+
+Usage: flashrom -p nic3com=bb:ss.f
+
+Signed-off-by: Christian Ruppert <spooky85@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r509 | uwe | 2009-05-14 16:51:14 +0200 (Thu, 14 May 2009) | 8 lines
+
+Cosmetics and eliminate unneeded vars as per IRC discussion (trivial).
+
+Build-tested and 'make PREFIX=/tmp/foo install' tested by me.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r508 | hailfinger | 2009-05-14 16:17:07 +0200 (Thu, 14 May 2009) | 5 lines
+
+Improve makefile structure a bit.
+
+Signed-off-by: Christian Ruppert <spooky85@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r507 | hailfinger | 2009-05-14 14:59:36 +0200 (Thu, 14 May 2009) | 13 lines
+
+Add a dummy SPI controller driver, similar to the dummy LPC/FWH/Parallel
+flasher driver.
+Does not support reading or writing the fake chip yet.
+
+flashrom --programmer dummy
+also enables the dummy SPI controller driver.
+
+Testing the dummy SPI driver revealed a RDID debug printing bug in the
+SPI core. Fix that as well.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r506 | stuge | 2009-05-14 14:41:00 +0200 (Thu, 14 May 2009) | 7 lines
+
+Fix spelling error in comment
+
+Author: raijin
+
+Signed-off-by: Daniel McLellan <daniel.mclellan@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r505 | hailfinger | 2009-05-14 00:51:27 +0200 (Thu, 14 May 2009) | 24 lines
+
+Generic status register prettyprinting for SST25*. Even if we don't tell
+the user about the areas the block locking bits correspond to, printing
+a detailed list of which lock bits are set is a definite improvement.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Sample output:
+[...]
+Probing for SST SST25VF032B, 4096 KB: RDID returned bf 25 4a.
+probe_spi_rdid_generic: id1 0xbf, id2 0x254a
+Chip status register is 1c
+Chip status register: Block Protect Write Disable (BPL) is not set
+Chip status register: Auto Address Increment Programming (AAI) is not
+set
+Chip status register: Bit 5 / Block Protect 3 (BP3) is not set
+Chip status register: Bit 4 / Block Protect 2 (BP2) is set
+Chip status register: Bit 3 / Block Protect 1 (BP1) is set
+Chip status register: Bit 2 / Block Protect 0 (BP0) is set
+Chip status register: Write Enable Latch (WEL) is not set
+Chip status register: Write In Progress (WIP/BUSY) is not set
+Found chip "SST SST25VF032B" (4096 KB) at physical address 0xffc00000.
+
+Acked-by: Cristi Magherusan <cristi.magherusan@net.utcluj.ro>
+
+------------------------------------------------------------------------
+r504 | hailfinger | 2009-05-14 00:19:12 +0200 (Thu, 14 May 2009) | 8 lines
+
+SST25 chips do not support page program, only byte program.
+
+Downgrade the chips from 256-byte writes to 1-byte writes. This fixes
+writing to them on ICH/VIA SPI masters.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: FENG Yu Ning <fengyuning1984@gmail.com>
+
+------------------------------------------------------------------------
+r503 | stuge | 2009-05-14 00:18:35 +0200 (Thu, 14 May 2009) | 7 lines
+
+Winbond W39V040A TEST_OK_ PROBE READ
+
+Thanks to Mateusz for testing and reporting!
+
+Signed-off-by: Mateusz Murawski <matowy@tlen.pl>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r502 | uwe | 2009-05-13 17:57:38 +0200 (Wed, 13 May 2009) | 9 lines
+
+Mark SST 39VF512 as fully tested.
+
+Tested with 3COM 3C905C: EtherLink 10/100 PCI (TX)
+http://www.coreboot.org/pipermail/coreboot/2009-May/048163.html
+
+Signed-off-by: Mateusz Murawski <matowy@tlen.pl>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r501 | uwe | 2009-05-13 14:01:57 +0200 (Wed, 13 May 2009) | 6 lines
+
+Fix nic3com.c build issues on *BSD (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r500 | hailfinger | 2009-05-13 13:40:08 +0200 (Wed, 13 May 2009) | 19 lines
+
+There are various reasons why a SPI command can fail. Among others, I
+have seen the following problems:
+- The SPI opcode is not supported by the controller. ICH-style
+controllers exhibit this if SPI config is locked down.
+- The address in in a prohibited area. This can happen on ICH for any
+access (BBAR) and for writes in chipset write protected areas.
+- There is no SPI controller.
+
+Introduce separate error codes for unsupported opcode and prohibited
+address.
+
+Add the ability to adjust REMS and RES addresses to the minium supported
+read address with the help of spi_get_valid_read_addr(). That function
+needs to call SPI controller specific functions like reading BBAR on
+ICH.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r499 | uwe | 2009-05-13 13:36:06 +0200 (Wed, 13 May 2009) | 54 lines
+
+Add support for 3COM NICs as "external programmer" and Atmel AT49BV512.
+
+This allows flashrom to identify, read, write, erase and verify flash chips
+on (some) 3COM network cards. The patch uses the external programmer
+infrastructure, the network card is basically treated as an external
+flash programmer.
+
+Usage:
+
+$ ./flashrom -p nic3com
+flashrom v0.9.0-r498
+Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400
+Calibrating delay loop... OK.
+Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000.
+No operations were specified.
+
+$ ./flashrom -p nic3com -E
+flashrom v0.9.0-r498
+Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400
+Calibrating delay loop... OK.
+Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000.
+Erasing flash chip... SUCCESS.
+
+$ ./flashrom -p nic3com -wv backup.bin
+flashrom v0.9.0-r498
+Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400
+Calibrating delay loop... OK.
+Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000.
+Flash image seems to be a legacy BIOS. Disabling checks.
+Programming page: 1023 at address: 0x0000ffc0
+Verifying flash... VERIFIED.
+
+$ ./flashrom -p nic3com -r backup.bin
+flashrom v0.9.0-r498
+Found NIC "3COM 3C905C: EtherLink 10/100 PCI (TX)" (10b7:9200), addr = 0xa400
+Calibrating delay loop... OK.
+Found chip "Atmel AT49BV512" (64 KB) at physical address 0xffff0000.
+Reading flash... done.
+
+I have tested this on actual hardware (see PCI IDs above) and all
+operations worked fine.
+
+Support for other 3COM cards will follow (I added some more which should
+be supportable by this code, but they're untested so far), as well as
+support for NICs from other vendors.
+
+The patch also adds support for the Atmel AT49BV512 which is soldered
+onto the 3COM NIC I used for testing.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Mateusz Murawski <matowy@tlen.pl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r498 | hailfinger | 2009-05-12 17:38:55 +0200 (Tue, 12 May 2009) | 44 lines
+
+Use helper functions chip_{read,write}[bwl] to access flash chips.
+
+The semantic patch I used in r418 to make the original conversion to
+accessor functions was missing one isomorphism:
+a[b] <=> *(a+b)
+
+The semantic patcher Coccinelle was used to create this patch. Semantic
+patch follows:
+@@
+typedef uint8_t;
+expression a;
+volatile uint8_t *b;
+@@
+- b[a]
++ *(b + a)
+@@
+expression a;
+volatile uint8_t *b;
+@@
+- *(b) = (a);
++ chip_writeb(a, b);
+@@
+volatile uint8_t *b;
+@@
+- *(b)
++ chip_readb(b)
+@@
+type T;
+T b;
+@@
+(
+ chip_readb
+|
+ chip_writeb
+)
+ (...,
+- (T)
+- (b)
++ b
+ )
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r497 | uwe | 2009-05-12 16:06:04 +0200 (Tue, 12 May 2009) | 7 lines
+
+The write_39sf020() and write_49f002() functions are identical except
+for whitespace differences, so drop one of them.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r496 | hailfinger | 2009-05-11 22:04:30 +0200 (Mon, 11 May 2009) | 8 lines
+
+Rename the STM50FLW register variable flash_addr used for block write
+protect handling. All other chips call it wrprotect which is less
+confusing.
+As a side benefit, flash_addr is now a name usable for other stuff.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r495 | hailfinger | 2009-05-11 17:46:43 +0200 (Mon, 11 May 2009) | 9 lines
+
+Print dummy programmer messages only if verbose mode is selected.
+Print the return value of dummy_chip_read[bwl].
+Align entries in programmer_table.
+
+This is a cosmetic patch and has no effect on code flow.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r494 | hailfinger | 2009-05-11 16:40:31 +0200 (Mon, 11 May 2009) | 19 lines
+
+When flashrom JEDEC code sends the ID command to the chip, it expects to
+see IDs in the default flash location. However, sometimes the chip does
+not react to the ID command, either because it doesn't understand the
+command or because the command never reached it.
+One way to detect this is to compare ID output with flash chip contents
+for the same location. If they are identical, there is a high chance
+you're not actually seeing ID output. Warn the user in that case.
+
+This patch helps a lot when a chip is not recognized and we want to
+check if the probe responses are real IDs or just random flash chip
+contents.
+
+This should probably be added to all probe functions, but probe_jedec is
+called for all sizes and thus flashrom will check this condition at
+least once per size, making sure we can cross-match the warning.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: FENG Yu Ning <fengyuning1984@gmail.com>
+
+------------------------------------------------------------------------
+r493 | hailfinger | 2009-05-11 16:13:25 +0200 (Mon, 11 May 2009) | 12 lines
+
+Flash mapping/unmapping was performed without an abstraction layer, so
+even the dummy flasher caused memory mappings to be set up.
+Add map/unmap functions to the external flasher abstraction.
+
+Fix a possible scribble-over-low-memory corner case which fortunately
+never triggered so far.
+
+With this patch, --programmer dummy works fine as non-root.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r492 | hailfinger | 2009-05-11 16:01:17 +0200 (Mon, 11 May 2009) | 12 lines
+
+Add lock bit handling (printing, setting and checking) to SST FWH chips
+and abort any writes to locked sectors.
+Verbose mode gives you all the info. Normal mode only tells you of
+unlocking failed, but gives enough details to debug.
+
+Add a comment about flash register placement to flashrom.c.
+
+Thanks to Uwe for testing multiple iterations of this patch.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r491 | hailfinger | 2009-05-10 16:11:07 +0200 (Sun, 10 May 2009) | 25 lines
+
+Create a SB600 SPI detection heuristic.
+
+I know that the data sheets say we can't read the ROM straps, but
+creative interpretation of the data sheets yielded a heuristic which
+should work pretty well.
+
+NOTE: If you test this, make sure you power down and _unplug_ the
+machine for a few minutes before you boot and run flashrom with this
+patch.
+If the machine is not unplugged for some time, the test will yield
+incorrect results.
+If you run a slightly older flashrom version than svn HEAD, the test
+will yield incorrect results.
+If you run any flashrom version (except svn HEAD plus this patch) after
+poweron, the test will yield incorrect results.
+
+Explanation:
+Older flashrom versions unconditionally write to registers which are
+used for this heuristic. These registers are in the S5 power domain, so
+even powering down does not clear them, you really have to unplug the
+machine and remove the battery if this is a laptop.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r490 | uwe | 2009-05-09 16:26:04 +0200 (Sat, 09 May 2009) | 6 lines
+
+Add support for EPoX EP-8K5A2 and separate out common VT823x board enable code.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r489 | hailfinger | 2009-05-09 09:32:30 +0200 (Sat, 09 May 2009) | 5 lines
+
+Kill one superfluous variable and improve code readability.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r488 | hailfinger | 2009-05-09 09:27:23 +0200 (Sat, 09 May 2009) | 16 lines
+
+Fix Elan SC520 handling.
+
+flashbase is a variable which should never be set outside chipset code.
+It is only used to calculate the base address of the flash space at
+exactly one location in the code.
+
+Setting flashbase during probe caused subsequent probes to fail unless
+special handling code was used. We had such code and it caused every
+probe except the first to fail on Elan SC520.
+
+Remove the superfluous flashbase assignment and simplify the rest of the
+code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r487 | hailfinger | 2009-05-09 09:24:23 +0200 (Sat, 09 May 2009) | 13 lines
+
+Trim default ICH SPI delay from 1000 to 10 microseconds. Since many
+commands take around 10 microseconds to complete, it is totally
+pointless to wait for 1000 microseconds before checking the status
+again.
+
+This patch is tested and reduced write time on ICH7 with SST25VF080B
+from over one hour to 62 seconds.
+
+Thanks to Ali Nadalizadeh for testing!
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Myles Watson <mylesgw@gmail.com>
+
+------------------------------------------------------------------------
+r486 | hailfinger | 2009-05-09 04:34:18 +0200 (Sat, 09 May 2009) | 10 lines
+
+Convert all flashchips.c entries with SPI programing to the 256-byte
+version by default.
+
+Change the flashchips entry for SST SST25VF080B to 1-byte writing.
+
+Tested-by: Ali Nadalizadeh.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r485 | hailfinger | 2009-05-09 04:30:21 +0200 (Sat, 09 May 2009) | 15 lines
+
+Chips like the SST SST25VF080B can only handle single byte writes
+outside AAI mode.
+
+Change SPI architecture to handle 1-byte chunk chip writing differently
+from 256-byte chunk chip writing.
+
+Annotate SPI chip write functions with _256 or _1 suffix denoting the
+number of bytes they write at maximum.
+
+The 1-byte chunk writing is cut-n-pasted to different SPI drivers right
+now. A later patch can move them to the generic spi_chip_write_1.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r484 | hailfinger | 2009-05-09 04:09:45 +0200 (Sat, 09 May 2009) | 11 lines
+
+Until the ICH SPI driver can handle preopcodes as standalone opcodes, we
+should handle such special opcode failure gracefully on ICH and
+compatible chipsets.
+
+This fixes chip erase on almost all ICH+VIA SPI masters.
+
+Thanks to Ali Nadalizadeh for helping track down this bug!
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r483 | hailfinger | 2009-05-09 02:54:55 +0200 (Sat, 09 May 2009) | 10 lines
+
+Add a dummy external flasher which just prints each operation.
+
+Usage:
+flashrom --programmer dummy
+
+This is a great way to test flashrom without root access.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r482 | uwe | 2009-05-09 02:47:04 +0200 (Sat, 09 May 2009) | 7 lines
+
+Split vendor name and board name into two fields as preparation
+for wiki output of supported stuff.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r481 | hailfinger | 2009-05-09 02:27:07 +0200 (Sat, 09 May 2009) | 5 lines
+
+Add --programmer to help text and man page.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r477 | uwe | 2009-05-08 19:50:51 +0200 (Fri, 08 May 2009) | 6 lines
+
+Make chipset list alphabetically ordered as the other lists.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r476 | hailfinger | 2009-05-08 19:43:22 +0200 (Fri, 08 May 2009) | 14 lines
+
+Add external flasher support:
+- Read/write accesses through function pointers
+- Command line parameter for internal/external flasher
+- Board and chipset setup moved to internal init function
+- Shutdown stuff moved to internal shutdown function
+
+As a side benefit, this will allow us to undo chipset write enable
+during shutdown.
+
+Tested by Uwe on real hardware.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r475 | hailfinger | 2009-05-08 19:15:15 +0200 (Fri, 08 May 2009) | 5 lines
+
+Re-add a line which got deleted in r473 by accident.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r474 | uwe | 2009-05-08 18:23:34 +0200 (Fri, 08 May 2009) | 8 lines
+
+Keep list of boards alphabetically sorted. This is (among other things)
+useful/required for the -L output and the upcoming wiki-syntax output of
+supported boards.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r473 | hailfinger | 2009-05-08 14:49:03 +0200 (Fri, 08 May 2009) | 11 lines
+
+Flashrom assumes that the flash chip contents are available via mmap if
+no read function is defined. This special case is handled in lots of
+places all over the code.
+
+Remove the special case and use the read_memmapped function. Not only
+does this allow us to fix a read bug in flashrom I recently uncovered on
+ICH SPI, it also allows us to add support for Paraflasher to flashrom.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r472 | uwe | 2009-05-07 15:24:49 +0200 (Thu, 07 May 2009) | 10 lines
+
+Store and display chipset test status (not only chip status).
+The list of tested chipsets is synced from the wiki.
+
+Also, split the chipset vendor and name into two fields for easier
+wiki-syntax output later.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r471 | hailfinger | 2009-05-07 02:59:53 +0200 (Thu, 07 May 2009) | 7 lines
+
+Always print the flashrom version as first output line.
+
+Suggested by Peter Stuge.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r470 | hailfinger | 2009-05-06 23:54:22 +0200 (Wed, 06 May 2009) | 8 lines
+
+ASD chips may exist, but all available docs suggest they are just
+rebranded Winbond chips with Winbond IDs.
+The ASD vendor/chip IDs in flash.h are very likely just misinterpreted
+LHA headers.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r469 | stuge | 2009-05-06 17:05:39 +0200 (Wed, 06 May 2009) | 5 lines
+
+Clarify error message in enable_flash_sb600() a little.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r468 | hailfinger | 2009-05-06 15:59:44 +0200 (Wed, 06 May 2009) | 9 lines
+
+Improve SST25 status register routines:
+- Using a 4-bit index into an array with 8 elements leads to
+out-of-bounds accesses. Use proper bit masking to fix this.
+- Factor out common SST25 status register printing.
+- Use the common SST25 status register printing for SST25VF080B.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r467 | hailfinger | 2009-05-06 15:51:44 +0200 (Wed, 06 May 2009) | 6 lines
+
+Revert r466 because it introduced a bug:
+If unprotect succeeded, it will print "SB600 unprotect failed".
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r466 | stuge | 2009-05-06 15:43:26 +0200 (Wed, 06 May 2009) | 5 lines
+
+Cleanup redundant condition and clarify message a little.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r465 | stuge | 2009-05-06 15:38:55 +0200 (Wed, 06 May 2009) | 5 lines
+
+Touch up some error messages in enable_flash_cs5536().
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r464 | hailfinger | 2009-05-06 02:35:31 +0200 (Wed, 06 May 2009) | 6 lines
+
+Clean up the SB400 chipset enable code. Use pci_dev_find() instead of
+setting up a filter and iterating over PCI devices.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r463 | hailfinger | 2009-05-06 00:50:07 +0200 (Wed, 06 May 2009) | 13 lines
+
+Rewrite the SB600 chipset enable function:
+- Check for read/write protected regions first.
+- Region protection is write-once according to the data sheets. Check if
+the write succeeded. Don't write if the region is not protected.
+- Verbose region protection dumping.
+- Improve readability of BAR mapping code.
+- Align BAR mapping to a page boundary (4k) instead of a 16k boundary.
+
+This patch prepares the code for a SPI detection heuristic.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r462 | myles | 2009-05-05 23:08:36 +0200 (Tue, 05 May 2009) | 6 lines
+
+Here is a fix for chipset_enable.c when there is not /dev/cpu. Open
+fails so there is no reason to lseek in. Actually this is a trivial fix
+for a bad return value from open.
+
+Signed-off-by: Bertrand Jacquin <beber@meleeweb.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+------------------------------------------------------------------------
+r461 | stuge | 2009-05-05 18:34:53 +0200 (Tue, 05 May 2009) | 7 lines
+
+SST25VF080B TEST_OK_ ERASE WRITE
+
+As reported by A. Spamlover. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r460 | uwe | 2009-05-05 18:15:46 +0200 (Tue, 05 May 2009) | 7 lines
+
+Some cosmetics in README and manpage. Also, move more stuff to the manpage
+where it belongs (this also eliminates some duplicated contents).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r459 | hailfinger | 2009-05-05 00:33:50 +0200 (Tue, 05 May 2009) | 10 lines
+
+Force enabling SPI mode for SB600 is a bad idea and leads to hangs.
+
+Only access LPC ROM if we boot via LPC ROM. Only access SPI ROM if we
+boot via SPI ROM.
+The code to force enable SPI is commented out in case someone wants to
+reenable it for a particular board with LPC and SPI flash.
+
+Signed-off-by: Zheng Bao <zheng.bao@amd.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r458 | stuge | 2009-05-04 23:03:59 +0200 (Mon, 04 May 2009) | 7 lines
+
+SST25VF080B TEST_OK_READ
+
+Per report from from Henning Fleddermann. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r457 | hailfinger | 2009-05-04 14:29:59 +0200 (Mon, 04 May 2009) | 5 lines
+
+Onwards with development. Re-add the svn revision to the version string.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r454 | hailfinger | 2009-05-04 14:18:10 +0200 (Mon, 04 May 2009) | 5 lines
+
+flashrom 0.9.0
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r453 | stuge | 2009-05-04 01:33:05 +0200 (Mon, 04 May 2009) | 6 lines
+
+Complement the README file with build instructions for the platforms it
+currently compiles on.
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r452 | hailfinger | 2009-05-01 18:34:32 +0200 (Fri, 01 May 2009) | 8 lines
+
+Fix compilation on Solaris and tell people how to compile flashrom on
+Solaris, Darwin/Mac OS X and DragonFly BSD.
+
+Thanks to Joerg Schilling and Patrick Georgi for the Solaris part.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r451 | stuge | 2009-05-01 16:52:50 +0200 (Fri, 01 May 2009) | 5 lines
+
+Mention that flashrom can also verify flash contents.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r450 | stuge | 2009-05-01 16:49:49 +0200 (Fri, 01 May 2009) | 5 lines
+
+Fix usage to show that vendor: is optional in the -m parameter.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r449 | hailfinger | 2009-05-01 14:22:17 +0200 (Fri, 01 May 2009) | 7 lines
+
+Some functions take no arguments. Make that explicit in the associated
+prototypes.
+This avoids a warning on some compilers and is a correctness issue.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r448 | hailfinger | 2009-05-01 13:00:39 +0200 (Fri, 01 May 2009) | 8 lines
+
+Add Li-Ta (Ollie) Lo to the author list.
+He started flashrom back in 2000.
+
+Thanks to Ron for pointing this out.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r447 | hailfinger | 2009-05-01 12:53:49 +0200 (Fri, 01 May 2009) | 7 lines
+
+Since the command line interface for flashrom will change for 1.0
+(all-caps or no-caps for short options, exclude range syntax, etc.) we
+should tell users in the man page and the usage message about this.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r446 | stuge | 2009-04-30 01:22:33 +0200 (Thu, 30 Apr 2009) | 7 lines
+
+flashrom: Macronix MX25L1605 TEST_OK_ PROBE READ ERASE WRITE
+
+Per report from Aldrik Dunbar. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r445 | hailfinger | 2009-04-28 14:56:04 +0200 (Tue, 28 Apr 2009) | 7 lines
+
+There are still some tweaks necessary to get Flashrom to build on
+DragonFly, but this helps a lot.
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r444 | oxygene | 2009-04-26 21:47:23 +0200 (Sun, 26 Apr 2009) | 5 lines
+
+Enable scan-build for flashrom.
+
+Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
+Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
+
+------------------------------------------------------------------------
+r443 | hailfinger | 2009-04-26 00:07:28 +0200 (Sun, 26 Apr 2009) | 19 lines
+
+Original v2 revision: 4211
+
+The flashrom makefile wants to redirect both stdout and stderr to
+/dev/null for one compile test.
+The old variant of using &>/dev/null works on bash and zsh, but not on
+dash and tcsh. dash and tcsh interpret it as "background command and
+truncate /dev/null" which is not what we want. >& works on tcsh and
+bash, but it is not POSIX compliant.
+Since make uses /bin/sh and /bin/sh has to be POSIX compliant, we can
+use the POSIX variant of stderr and stdout redirection.
+
+>/dev/null 2>&1
+is POSIX compliant. This is specified in SuSv3, Shell Command Language,
+sections 2.7.2 and 2.7.6.
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r442 | uwe | 2009-04-24 18:17:41 +0200 (Fri, 24 Apr 2009) | 8 lines
+
+Original v2 revision: 4205
+
+MAX may already be defined. Also, fix smaller cosmetics (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r441 | stuge | 2009-04-24 00:51:56 +0200 (Fri, 24 Apr 2009) | 7 lines
+
+Original v2 revision: 4200
+
+flashrom: Support MX25L3235D
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r440 | uwe | 2009-04-23 16:57:55 +0200 (Thu, 23 Apr 2009) | 9 lines
+
+Original v2 revision: 4196
+
+Don't duplicate option description in README, the manpage already has
+that info. Also, additional small cosmetic fix.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r439 | hailfinger | 2009-04-22 15:33:43 +0200 (Wed, 22 Apr 2009) | 23 lines
+
+Original v2 revision: 4177
+
+All "unknown xy SPI chip" entries claim to have status UNTESTED for
+probe/read/erase/write. That is incorrect.
+
+A bit of confusion comes from how the #defines are named. We call them
+TEST_BAD_*, but the message printed by flashrom says:
+"This flash part has status NOT WORKING for operations:"
+
+Something that is unimplemented is definitely not working.
+
+Neither of the chip entries mentioned above has erase or write functions
+implemented, so erase and write are not working.
+Since their size is unknown, we can't read them in. That means read is
+not working as well.
+Probing is a different matter. If a chip-specific probe function had
+matched, we wouldn't have to handle the chip with the "unknown xy SPI
+chip" fallback. I'm tempted to call that "not working" as well, but I'm
+open to discussion on this point.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r438 | hailfinger | 2009-04-22 01:03:20 +0200 (Wed, 22 Apr 2009) | 10 lines
+
+Original v2 revision: 4161
+
+flashrom: Add support for Gigabyte GA-MA790FX-DQ6. This board uses
+IT8718F LPC->SPI translation for the flash chip.
+
+Tested by Mateusz Murawski.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Mateusz Murawski <matowy@tlen.pl>
+
+------------------------------------------------------------------------
+r437 | stuge | 2009-04-21 03:47:16 +0200 (Tue, 21 Apr 2009) | 7 lines
+
+Original v2 revision: 4150
+
+flashrom: Support Macronix MX2512805D flash chip
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r436 | stuge | 2009-04-21 03:46:07 +0200 (Tue, 21 Apr 2009) | 7 lines
+
+Original v2 revision: 4149
+
+flashrom: Trivial indent fix
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r435 | hailfinger | 2009-04-21 00:54:13 +0200 (Tue, 21 Apr 2009) | 8 lines
+
+Original v2 revision: 4146
+
+After verification in datasheets, all MX25 accept the same opcodes
+0x60 and 0xC7 for Chip Erase.
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r434 | stuge | 2009-04-20 14:38:17 +0200 (Mon, 20 Apr 2009) | 13 lines
+
+Original v2 revision: 4142
+
+flashrom: board_enables: reconstruct table.
+
+This patch restores the pciid based board matching table. It makes this
+table readable and hackable again, and the only disadvantage is that the
+right margin is way beyond the rather dogmatic 80. All 0x0000 pci ids have
+been string replaced by 0 to more easily spot missing ids, and extra
+comments have been added to explain how the various entries are used.
+
+Signed-Off-By: Luc Verhaegen <libv@skynet.be>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r433 | stuge | 2009-04-20 14:34:30 +0200 (Mon, 20 Apr 2009) | 7 lines
+
+Original v2 revision: 4141
+
+flashrom: Trivial README change Flashrom->flashrom
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r432 | stuge | 2009-04-20 01:24:26 +0200 (Mon, 20 Apr 2009) | 7 lines
+
+Original v2 revision: 4139
+
+flashrom: MX25L1605 and 1635 accept Chip Erase opcodes 60 and C7
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r431 | hailfinger | 2009-04-20 01:04:00 +0200 (Mon, 20 Apr 2009) | 7 lines
+
+Original v2 revision: 4138
+
+Add MX25L1635D support, as discussed on #coreboot.
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r430 | stuge | 2009-04-18 01:01:45 +0200 (Sat, 18 Apr 2009) | 7 lines
+
+Original v2 revision: 4132
+
+flashrom: Add VIA PC3500G board. It has SPI flash behind ITE8716 on LPC.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: illdred <illdred@gmail.com>
+
+------------------------------------------------------------------------
+r429 | uwe | 2009-04-15 12:52:49 +0200 (Wed, 15 Apr 2009) | 8 lines
+
+Original v2 revision: 4117
+
+Some coding style and consistency fixes (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r428 | uwe | 2009-04-13 23:35:49 +0200 (Mon, 13 Apr 2009) | 8 lines
+
+Original v2 revision: 4107
+
+Fix typo. Add missing copyright year.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r427 | uwe | 2009-04-11 15:59:00 +0200 (Sat, 11 Apr 2009) | 8 lines
+
+Original v2 revision: 4092
+
+Mention a few more flash chip packages in README/manpage.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r426 | uwe | 2009-04-10 16:49:14 +0200 (Fri, 10 Apr 2009) | 8 lines
+
+Original v2 revision: 4089
+
+Fix typo.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r425 | uwe | 2009-04-10 16:41:29 +0200 (Fri, 10 Apr 2009) | 15 lines
+
+Original v2 revision: 4088
+
+Various manpage / README fixes:
+
+ - Improve description a bit, especially wrt chip packages and
+   protocols.
+
+ - Add some missing parameters to manpage option descriptions.
+
+ - Remove long obsolete DoC support note.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r424 | rminnich | 2009-04-09 16:28:36 +0200 (Thu, 09 Apr 2009) | 9 lines
+
+Original v2 revision: 4086
+
+Fixed the typo should indeed be a 0x2e.
+Tested on an iWILL DK8-HTX board.
+
+Signed-off-by: Mondrian nuessle <nuessle@uni-hd.de>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+
+------------------------------------------------------------------------
+r423 | stuge | 2009-03-30 15:20:01 +0200 (Mon, 30 Mar 2009) | 11 lines
+
+Original v2 revision: 4031
+
+flashrom: Board enable support for HP DL145 G3.
+
+This is a BCM5785 based machine, WP# and TLB# need to be deasserted using
+GPIO 2 and 5 from the PM registers of the southbridge.
+This is very similar to the x3455 implementation.
+
+Signed-off-by: Mondrian Nuessle <nuessle@uni-hd.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r422 | hailfinger | 2009-03-19 13:18:13 +0100 (Thu, 19 Mar 2009) | 8 lines
+
+Original v2 revision: 4020
+
+Move the Atmel AT45 comments about block and page sizes from the end of
+the struct to the individual struct members to improve readability.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r421 | stepan | 2009-03-17 15:39:25 +0100 (Tue, 17 Mar 2009) | 21 lines
+
+Original v2 revision: 4012
+
+This patch adds "high coreboot table support" to coreboot version 2.
+
+Some bootloaders seem to overwrite memory starting at 0x600, thus destroying
+the coreboot table integrity, rendering the table useless.
+
+By moving the table to the high tables area (if it's activated), this problem
+is fixed.
+
+In order to move the table, a 40 bytes mini coreboot table with a single sub
+table is placed at 0x500/0x530 that points to the real coreboot table. This is
+comparable to the ACPI RSDT or the MP floating table.
+
+This patch also adds "table forward" support to flashrom and nvramtool.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+
+------------------------------------------------------------------------
+r420 | hailfinger | 2009-03-06 23:26:00 +0100 (Fri, 06 Mar 2009) | 11 lines
+
+Original v2 revision: 3984
+
+FreeBSD definitions of (read|write)[bwl] collide with our own. Before we
+attempt trickery, we can simply rename the accessor functions.
+
+Patch created with the help of Coccinelle.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Idwer Vollering <idwer_v@hotmail.com>
+Acked-by: Patrick Georgi <patrick@georgi-clan.de>
+
+------------------------------------------------------------------------
+r419 | hailfinger | 2009-03-06 01:40:25 +0100 (Fri, 06 Mar 2009) | 112 lines
+
+Original v2 revision: 3973
+
+During the conversion of flash chip accesses to helper functions, I
+spotted assignments to volatile variables which were neither placed
+inside the mmapped ROM area nor were they counters.
+Due to the use of accessor functions, volatile usage can be reduced
+significantly because the accessor functions take care of actually
+performing the reads/writes correctly.
+
+The following semantic patch spotted them (linebreak in python string
+for readability reasons, please remove before usage):
+@r exists@
+expression b;
+typedef uint8_t;
+volatile uint8_t a;
+position p1;
+@@
+ a@p1 = readb(b);
+
+@script:python@
+p1 << r.p1;
+a << r.a;
+b << r.b;
+@@
+print "* file: %s line %s has assignment to unnecessarily volatile
+variable: %s = readb(%s);" % (p1[0].file, p1[0].line, a, b)
+
+Result was:
+HANDLING: sst28sf040.c
+* file: sst28sf040.c line 44 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 43 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 42 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 41 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 40 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 39 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 38 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 58 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 57 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 56 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 55 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 54 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 53 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+* file: sst28sf040.c line 52 has assignment to unnecessarily volatile
+variable: tmp = readb(TODO: Binary);
+
+The following semantic patch uses the spatch builtin match printing
+functionality by prepending a "*" to the line with the pattern:
+@@
+expression b;
+typedef uint8_t;
+volatile uint8_t a;
+@@
+* a = readb(b);
+
+Result is:
+HANDLING: sst28sf040.c
+diff =
+--- sst28sf040.c        2009-03-06 01:04:49.000000000 +0100
+@@ -35,13 +35,6 @@ static __inline__ void protect_28sf040(v
+        /* ask compiler not to optimize this */
+        volatile uint8_t tmp;
+-       tmp = readb(bios + 0x1823);
+-       tmp = readb(bios + 0x1820);
+-       tmp = readb(bios + 0x1822);
+-       tmp = readb(bios + 0x0418);
+-       tmp = readb(bios + 0x041B);
+-       tmp = readb(bios + 0x0419);
+-       tmp = readb(bios + 0x040A);
+ }
+ static __inline__ void unprotect_28sf040(volatile uint8_t *bios)
+@@ -49,13 +42,6 @@ static __inline__ void unprotect_28sf040
+        /* ask compiler not to optimize this */
+        volatile uint8_t tmp;
+-       tmp = readb(bios + 0x1823);
+-       tmp = readb(bios + 0x1820);
+-       tmp = readb(bios + 0x1822);
+-       tmp = readb(bios + 0x0418);
+-       tmp = readb(bios + 0x041B);
+-       tmp = readb(bios + 0x0419);
+-       tmp = readb(bios + 0x041A);
+ }
+ static __inline__ int erase_sector_28sf040(volatile uint8_t *bios,
+
+It's arguably a bit easier to read if you get used to the leading "-"
+for matching lines.
+
+This patch was enabled by Coccinelle:
+http://www.emn.fr/x-info/coccinelle/
+
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Joseph Smith <joe@settoplinux.org>
+-- 
+http://www.hailfinger.org/
+
+------------------------------------------------------------------------
+r418 | hailfinger | 2009-03-05 20:24:22 +0100 (Thu, 05 Mar 2009) | 52 lines
+
+Original v2 revision: 3971
+
+flashrom: Use helper functions to access flash chips.
+
+Right now we perform direct pointer manipulation without any abstraction
+to read from and write to memory mapped flash chips. That makes it
+impossible to drive any flasher which does not mmap the whole chip.
+
+Using helper functions readb() and writeb() allows a driver for external
+flash programmers like Paraflasher to replace readb and writeb with
+calls to its own chip access routines.
+
+This patch has the additional advantage of removing lots of unnecessary
+casts to volatile uint8_t * and now-superfluous parentheses which caused
+poor readability.
+
+I used the semantic patcher Coccinelle to create this patch. The
+semantic patch follows:
+@@
+expression a;
+typedef uint8_t;
+volatile uint8_t *b;
+@@
+- *(b) = (a);
++ writeb(a, b);
+@@
+volatile uint8_t *b;
+@@
+- *(b)
++ readb(b)
+@@
+type T;
+T b;
+@@
+(
+ readb
+|
+ writeb
+)
+ (...,
+- (T)
+- (b)
++ b
+ )
+
+In contrast to a sed script, the semantic patch performs type checking
+before converting anything.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: FENG Yu Ning <fengyuning1984@gmail.com>
+Tested-by: Joe Julian
+
+------------------------------------------------------------------------
+r417 | stuge | 2009-02-25 09:07:33 +0100 (Wed, 25 Feb 2009) | 7 lines
+
+Original v2 revision: 3958
+
+flashrom: Add SST25VF040.REMS with TEST_OK_ PROBE READ
+
+Signed-off-by: Zheng Bao <zheng.bao@amd.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r416 | stuge | 2009-02-22 22:07:28 +0100 (Sun, 22 Feb 2009) | 9 lines
+
+Original v2 revision: 3956
+
+flashrom: SST29EE020A TEST_OK_ PROBE READ ERASE WRITE
+
+Report by Holger Mickler. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r415 | stuge | 2009-02-09 21:26:14 +0100 (Mon, 09 Feb 2009) | 13 lines
+
+Original v2 revision: 3932
+
+flashrom: Fix broken flash chip base address logic
+
+Elan SC520 requries us to deal with flash chip base addresses at locations
+other than top of 4GB. The logic for that was incorrectly triggered also when
+a board had more than one flash chip. This patch will honor flashbase only when
+probing for the first flash chip on the board, and look at top of 4GB for later
+chips.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Myles Watson <mylesgw@gmail.com>
+
+------------------------------------------------------------------------
+r414 | stuge | 2009-02-02 23:55:26 +0100 (Mon, 02 Feb 2009) | 7 lines
+
+Original v2 revision: 3927
+
+flashrom: MSI MS-7046 board enable
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: David Tiemann <davidtiemann@gmail.com>
+
+------------------------------------------------------------------------
+r413 | ruik | 2009-02-01 19:40:50 +0100 (Sun, 01 Feb 2009) | 9 lines
+
+Original v2 revision: 3926
+
+ Following patch fixes VIA SPI (VT8237S). It needs to have opcodes
+ initialized same way as ICH7.
+
+ Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+ Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r412 | hailfinger | 2009-01-28 01:27:54 +0100 (Wed, 28 Jan 2009) | 7 lines
+
+Original v2 revision: 3923
+
+Factor out read and erase functions from flashrom main().
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r411 | stuge | 2009-01-26 16:29:27 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3919
+
+flashrom: Add VT8237A PCI ID
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r410 | stuge | 2009-01-26 16:19:43 +0100 (Mon, 26 Jan 2009) | 9 lines
+
+Original v2 revision: 3918
+
+flashrom: Fix one dead increment and one dead assignment as found by clang.
+
+Thanks Patrick!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r409 | stuge | 2009-01-26 07:42:02 +0100 (Mon, 26 Jan 2009) | 9 lines
+
+Original v2 revision: 3917
+
+flashrom: Driver for ST M29F002T/NT/B. T/NT TEST_OK_ PROBE READ ERASE WRITE
+
+Test report from Julia. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Julia Longtin <juri@solarnetone.org>
+
+------------------------------------------------------------------------
+r408 | stuge | 2009-01-26 05:48:01 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3916
+
+flashrom: Fix copypaste error in r3913.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r407 | stuge | 2009-01-26 04:37:40 +0100 (Mon, 26 Jan 2009) | 13 lines
+
+Original v2 revision: 3913
+
+flashrom: SST25VF040B using 0x90 identification and AAI write.
+
+SST AAI is Auto Address Increment writing, a streamed write to the flash chip
+where the first write command sets a starting address and following commands
+simply append data. Unfortunately not supported by Winbond SPI masters.
+
+From July 2008.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r406 | stuge | 2009-01-26 04:23:50 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3912
+
+flashrom: Decode SST25VF040B status register, also from July 2008.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r405 | stuge | 2009-01-26 04:12:44 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3911
+
+flashrom: Intel Desktop Board D201GLY
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r404 | stuge | 2009-01-26 04:08:45 +0100 (Mon, 26 Jan 2009) | 10 lines
+
+Original v2 revision: 3910
+
+flashrom: Winbond SuperIO SPI driver.
+
+Developed and tested to work on Intel D201GLY in July 2008.
+Tested by a helpful person on IRC whose name I've since forgotten. Sorry!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r403 | stuge | 2009-01-26 03:34:51 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3909
+
+flashrom: Export Winbond SuperIO register access functions in board_enable.c.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r402 | stuge | 2009-01-26 03:20:56 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3908
+
+flashrom: Document exit() codes introduced in r3907.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r401 | stuge | 2009-01-26 03:04:19 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3907
+
+flashrom: exit(2) on /dev/mem open() failure and exit(3) on mmap() failure.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r400 | stuge | 2009-01-26 02:33:02 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3906
+
+flashrom: Add license header to physmap.c so everyone is happy. :)
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r399 | stuge | 2009-01-26 02:23:31 +0100 (Mon, 26 Jan 2009) | 11 lines
+
+Original v2 revision: 3905
+
+flashrom: Darwin / Mac OS X
+
+Through DirectIO from coresystems GmbH we now support Darwin/Mac OS X.
+DirectIO is available at http://www.coresystems.de/en/directio
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r398 | stuge | 2009-01-26 02:16:09 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3904
+
+flashrom: Small cleanup in Makefile.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r397 | stuge | 2009-01-26 02:10:48 +0100 (Mon, 26 Jan 2009) | 8 lines
+
+Original v2 revision: 3903
+
+flashrom: Abstract mmap() in physmap.c and only open /dev/mem on the first physmap() call.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r396 | stuge | 2009-01-26 01:39:57 +0100 (Mon, 26 Jan 2009) | 9 lines
+
+Original v2 revision: 3901
+
+flashrom: Change flashrom.c:map_flash_registers() from int to void.
+
+The function exit()s on failure, and no callers check the return value.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r395 | stuge | 2009-01-26 01:19:36 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3900
+
+flashrom: Forgot some things in r3899.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r394 | stuge | 2009-01-26 01:15:56 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3899
+
+flashrom: Little readability improvement in cbtable.c:coreboot_init()
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r393 | stuge | 2009-01-26 01:07:25 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3898
+
+flashrom: Change FreeBSD #ifdef into #if defined()
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r392 | stuge | 2009-01-26 00:59:30 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3897
+
+flashrom: Make Makefile a bit more portable. Shell echo doesn't always know -n.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r391 | stuge | 2009-01-26 00:55:12 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3896
+
+flashrom: Add dry Am29F080B Am29LV081B SST39VF080 definitions per data sheets.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r390 | stuge | 2009-01-26 00:52:45 +0100 (Mon, 26 Jan 2009) | 7 lines
+
+Original v2 revision: 3895
+
+flashrom: Beautify flash chip ID verbose printout a little, always use %02x.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r389 | stuge | 2009-01-25 21:41:51 +0100 (Sun, 25 Jan 2009) | 9 lines
+
+Original v2 revision: 3894
+
+flashrom: Fix stupid off-by-one error in erase verification.
+
+As reported by Jody McIntyre. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r388 | stuge | 2009-01-25 00:01:08 +0100 (Sun, 25 Jan 2009) | 9 lines
+
+Original v2 revision: 3893
+
+flashrom: ST M50FW080 TEST_OK_ PROBE READ ERASE WRITE
+
+Report by Jody McIntyre. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r387 | stuge | 2009-01-24 02:32:40 +0100 (Sat, 24 Jan 2009) | 9 lines
+
+Original v2 revision: 3892
+
+flashrom: SST25VF080B TEST_OK_PROBE
+
+Report by Scaldov M.V. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r386 | stuge | 2009-01-23 06:23:06 +0100 (Fri, 23 Jan 2009) | 7 lines
+
+Original v2 revision: 3890
+
+flashrom: Check all mmap() calls and print helpful Linux error message.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r385 | stuge | 2009-01-22 23:53:59 +0100 (Thu, 22 Jan 2009) | 9 lines
+
+Original v2 revision: 3889
+
+flashrom: Provide some hints for the user in case /dev/mem mmap fails.
+
+resolves #121
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r384 | stuge | 2009-01-18 07:39:32 +0100 (Sun, 18 Jan 2009) | 8 lines
+
+Original v2 revision: 3869
+
+flashrom: Fix ICH9 locking register address and add important debug output.
+
+Signed-off-by: FENG yu ning <fengyuning1984@gmail.com>
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: FENG yu ning <fengyuning1984@gmail.com>
+
+------------------------------------------------------------------------
+r383 | stuge | 2009-01-15 03:13:18 +0100 (Thu, 15 Jan 2009) | 7 lines
+
+Original v2 revision: 3862
+
+flashrom: Add ICH opcode debugging.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r382 | hailfinger | 2009-01-15 01:48:24 +0100 (Thu, 15 Jan 2009) | 18 lines
+
+Original v2 revision: 3861
+
+Similarly to flashchips array, this patch intends to make the table
+board_pciid_enables more readable.
+
+Signed-off-by: Stephan Guilloux <stephan.guilloux@free.fr>
+
+> What real problem does this solve?
+
+1. Next time someone adds a new struct member, we avoid mistakes of
+ordering of initializers
+2. we avoid mistakes in the first place.
+
+The .x = y stuff was added for a (good) reason, I think this is an
+improvement.
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r381 | stuge | 2009-01-13 15:32:27 +0100 (Tue, 13 Jan 2009) | 7 lines
+
+Original v2 revision: 3860
+
+flashrom: Always print address when verification fails, not only with -V.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r380 | stuge | 2009-01-12 22:31:14 +0100 (Mon, 12 Jan 2009) | 11 lines
+
+Original v2 revision: 3859
+
+flashrom: Board enable for GIGABYTE GA-MA78G-DS3H
+
+This board has 2x MX25L8005 flash chips behind an IT8718F LPC->SPI bridge.
+The board uses GIGABYTE's patented BIOS failover technology, and at this point
+we do not know how to control which of the two chips flashrom actually hits.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Yul Rottmann <yulrottmann@bitel.net>
+
+------------------------------------------------------------------------
+r379 | stuge | 2009-01-12 22:28:03 +0100 (Mon, 12 Jan 2009) | 7 lines
+
+Original v2 revision: 3858
+
+flashrom: IT8718F works just like IT8716F.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Yul Rottmann <yulrottmann@bitel.net>
+
+------------------------------------------------------------------------
+r378 | stuge | 2009-01-12 22:00:35 +0100 (Mon, 12 Jan 2009) | 9 lines
+
+Original v2 revision: 3857
+
+flashrom: Check return value of fscanf()/fwrite()/fread()
+
+Fix build error on distros with warn_unused_result attributes in glibc.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Yul Rottmann <yulrottmann@bitel.net>
+
+------------------------------------------------------------------------
+r377 | stuge | 2009-01-11 04:31:02 +0100 (Sun, 11 Jan 2009) | 9 lines
+
+Original v2 revision: 3855
+
+flashrom: Update usage in README
+
+Mimicked from flashrom.c
+
+Signed-off-by: Idwer Vollering <vidwer@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r376 | hailfinger | 2009-01-08 17:53:13 +0100 (Thu, 08 Jan 2009) | 13 lines
+
+Original v2 revision: 3853
+
+Add erase and write functions to the following chip definitions:
+
+AT25DF021 AT25DF041A AT25DF081 AT25DF161 AT25DF321 AT25DF321A AT25DF641
+AT25F512B AT25FS010 AT25FS040 AT26DF081A AT26DF161 AT26DF161A AT26DF321
+AT26F004
+
+Straight from the data sheets, untested because I lack the hardware.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r375 | hailfinger | 2009-01-08 05:56:59 +0100 (Thu, 08 Jan 2009) | 14 lines
+
+Original v2 revision: 3852
+
+The flashrom man page has incomplete author/copyright sections and an
+incorrect license section.
+- Remove the copyright listings and refer the reader to the source
+  files.
+- Update the author list to those which have copyright messages in the
+source files.
+- Correct the license from GPL v2+ to (GPL v2, with some files under
+  later versions as well)
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r374 | hailfinger | 2009-01-08 04:40:17 +0100 (Thu, 08 Jan 2009) | 11 lines
+
+Original v2 revision: 3851
+
+This patch improves machine parseability and human readability of
+flashchips.c over what's currently in flashrom HEAD.
+The explicit initialization makes sure any future struct flashchip
+reordering is not needed. (Except for the case where we need arrays
+of some of the struct members.)
+
+Signed-off-by: Stephan Guilloux <mailto:stephan.guilloux@free.fr>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r373 | uwe | 2009-01-07 13:35:09 +0100 (Wed, 07 Jan 2009) | 8 lines
+
+Original v2 revision: 3850
+
+Add SST49LF020 support.
+
+Signed-off-by: Sven Schnelle <svens@stackframe.org>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r372 | uwe | 2009-01-07 13:15:46 +0100 (Wed, 07 Jan 2009) | 8 lines
+
+Original v2 revision: 3849
+
+Add AMD-768 chipset support.
+
+Signed-off-by: Sven Schnelle <svens@stackframe.org>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r371 | uwe | 2009-01-07 13:11:13 +0100 (Wed, 07 Jan 2009) | 8 lines
+
+Original v2 revision: 3848
+
+Add i631x LPC support.
+
+Signed-off-by: Sven Schnelle <svens@stackframe.org>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r370 | uwe | 2008-12-22 17:42:59 +0100 (Mon, 22 Dec 2008) | 10 lines
+
+Original v2 revision: 3834
+
+If you pass a bogus layout file to the -l option flashrom will segfault.
+Fix that by throwing an error instead.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r369 | uwe | 2008-12-22 17:40:45 +0100 (Mon, 22 Dec 2008) | 13 lines
+
+Original v2 revision: 3833
+
+Add another board-enable line for the Kontron 986LCD-M/mITX.
+
+There seem to be at least two versions of the board out there, and the
+subsystem IDs changed between the versions.
+
+Patch successfully tested on hardware.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r368 | stuge | 2008-12-22 15:12:08 +0100 (Mon, 22 Dec 2008) | 7 lines
+
+Original v2 revision: 3830
+
+flashrom: Initialize ICH SPI opcodes also for ICH9 and later.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r367 | stuge | 2008-12-15 03:32:11 +0100 (Mon, 15 Dec 2008) | 18 lines
+
+Original v2 revision: 3814
+
+* add a generic preop-opcode-pair table.
+
+* rename ich_check_opcodes to ich_init_opcodes.
+
+* let ich_init_opcodes do not need to access flashchip structure:
+  . move the definition of struct preop_opcode_pair to a better place
+  . remove preop_opcode_pairs from 'struct flashchip'
+  . modify ich_init_opcodes and generate_opcodes so that they do not access the flashchip structure
+
+* call ich_init_opcodes during chipset enable. Now OPCODES generation mechanism works.
+
+* fix a coding style mistake.
+
+Signed-off-by: FENG yu ning <fengyuning1984@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r366 | hailfinger | 2008-12-10 11:32:05 +0100 (Wed, 10 Dec 2008) | 10 lines
+
+Original v2 revision: 3809
+
+Add 28 flash chips of the MX29 series to the flashrom ID table and
+support the MX29LV040C.
+
+MX29LV040C probe and read support tested by khetzal on IRC.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r365 | hailfinger | 2008-12-09 00:51:45 +0100 (Tue, 09 Dec 2008) | 7 lines
+
+Original v2 revision: 3806
+
+Kill obsolete and misplaced comment.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r364 | stepan | 2008-12-08 19:16:58 +0100 (Mon, 08 Dec 2008) | 9 lines
+
+Original v2 revision: 3805
+
+Generates OPCODES struct from the ICH7/ICH9/VIA chipset if its SPI
+configuration is locked down.
+
+Signed-off-by: FENG yu ning <fengyuning1984@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r363 | stepan | 2008-12-08 19:15:10 +0100 (Mon, 08 Dec 2008) | 8 lines
+
+Original v2 revision: 3804
+
+Breaks chip info into multiple lines.
+
+Signed-off-by: FENG yu ning <fengyuning1984@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r362 | stuge | 2008-12-06 02:37:09 +0100 (Sat, 06 Dec 2008) | 18 lines
+
+Original v2 revision: 3803
+
+flashrom: Display test status in -L chip listing
+
+Looks like this:
+
+Supported flash chips:          Tested OK operations:   Known BAD operations:
+
+AMD Am29F002(N)BB                                       
+AMD Am29F002(N)BT               PROBE READ ERASE WRITE  
+AMD Am29F016D                                           
+AMD Am29F040B                   PROBE READ ERASE WRITE  
+AMD Am29LV040B                                          
+Atmel AT45CS1282                                        READ 
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r361 | stuge | 2008-12-05 12:58:43 +0100 (Fri, 05 Dec 2008) | 11 lines
+
+Original v2 revision: 3799
+
+flashrom: Add AMD SB700 flash enable
+
+This patch adds SB700 support to flashrom. The code for enabling the flash
+rom is the same as for SB600. It was tested (read, write, verify) with an
+ASUS M3A-H/HDMI which contains a Macronix MX25L8005.
+
+Signed-off-by: Niels Ole Salscheider <niels_ole@salscheider-online.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r360 | stuge | 2008-12-05 12:56:57 +0100 (Fri, 05 Dec 2008) | 9 lines
+
+Original v2 revision: 3798
+
+flashrom: Fix compilation of r3797 with gcc-4.3.2
+
+Thanks to Niels Ole Salscheider for the problem report.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r359 | stuge | 2008-12-05 03:22:30 +0100 (Fri, 05 Dec 2008) | 9 lines
+
+Original v2 revision: 3797
+
+flashrom: Check if erase succeeds and exit with error on failure.
+
+flashrom used to exit 0 even if erase failed. Not anymore.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r358 | hailfinger | 2008-12-04 01:58:10 +0100 (Thu, 04 Dec 2008) | 30 lines
+
+Original v2 revision: 3793
+
+Add RDID/REMS IDs for the following flash chips:
+
+SST_25VF512A_REMS
+SST_25VF010_REMS
+SST_25VF020_REMS
+SST_25VF040_REMS
+SST_25VF040B_REMS
+SST_25VF080_REMS
+SST_25VF080B_REMS
+SST_25VF032B_REMS
+SST_26VF016
+SST_26VF032
+W_25X16
+W_25X32
+W_25X64
+
+Straight from the data sheets.
+
+The REMS IDs help in case the RDID opcode is unavailable (due to opcode
+lockdown) or unsupported by the chip.
+
+Some day, we need to pair probe functions together with IDs. Multiple
+pairs can exist per chip and duplicating chip definitions does not
+really make sense.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r357 | stuge | 2008-12-04 00:36:48 +0100 (Thu, 04 Dec 2008) | 9 lines
+
+Original v2 revision: 3792
+
+flashrom: gcc thinks base could be used uninitialized, so shut it up.
+
+Bug from r3791.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r356 | stuge | 2008-12-03 22:39:56 +0100 (Wed, 03 Dec 2008) | 10 lines
+
+Original v2 revision: 3791
+
+flashrom: Fix bug in r3790
+
+If flashbase was set before probe_flash() it would only ever be used once, for
+the very first flash chip probe.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r355 | stuge | 2008-12-03 22:24:40 +0100 (Wed, 03 Dec 2008) | 10 lines
+
+Original v2 revision: 3790
+
+Replace #ifdefs for sc520 systems by run time probing.
+
+fixes #109
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r354 | stepan | 2008-11-29 16:07:15 +0100 (Sat, 29 Nov 2008) | 9 lines
+
+Original v2 revision: 3782
+
+Copyright update by Jason Wang for freshly written sb600 code.
+
+Signed-off-by:  Jason Wang<Qingpei.wang@amd.com>
+Reviewed-by:    Joe, Bao <Zheng.Bao@amd.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r353 | hailfinger | 2008-11-29 00:47:55 +0100 (Sat, 29 Nov 2008) | 7 lines
+
+Original v2 revision: 3781
+
+Declare special commands to support the Atmel AT25F512A.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r352 | hailfinger | 2008-11-29 00:45:27 +0100 (Sat, 29 Nov 2008) | 9 lines
+
+Original v2 revision: 3780
+
+If a chip has any TEST_BAD_* flag set, we don't even list the
+unsupported functions, giving the user the impression that the
+unsupported functions are tested.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r351 | uwe | 2008-11-28 22:36:51 +0100 (Fri, 28 Nov 2008) | 11 lines
+
+Original v2 revision: 3779
+
+Add support for the AMD/ATI SB600 southbridge SPI functionality.
+
+This has been tested by Uwe Hermann on an RS690/SB600 board.
+
+Signed-off-by: Jason Wang <Qingpei.Wang@amd.com>
+Reviewed-by: Joe Bao <zheng.bao@amd.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r350 | hailfinger | 2008-11-28 06:40:27 +0100 (Fri, 28 Nov 2008) | 10 lines
+
+Original v2 revision: 3776
+
+Add SST25VF080B flash chip support.
+This is the first chip which uses the infrastructure for alternative
+erase commands, namely spi_chip_erase_60_c7().
+
+Signed-off-by:  Jason Wang <Qingpei.Wang@amd.com>
+Reviewed-by:   Joe Bao <zheng.bao@amd.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r349 | hailfinger | 2008-11-28 02:25:00 +0100 (Fri, 28 Nov 2008) | 24 lines
+
+Original v2 revision: 3775
+
+Flashrom already has the following probe functions:
+- probe_spi_rdid with opcode 0x9f, usually 3 bytes ID
+- probe_spi_res with opcode 0xab, usually 1 byte ID
+We are missing the following probe function:
+- probe_spi_rems with opcode 0x90, usually 2 bytes ID
+
+RDID provides best specifity (manufacturer, device class and device) and
+RES is supported by quite a few old chips. However, RES only returns one
+byte and there are multiple flash chips with different sizes on the
+market and all of them have the same RES ID.
+REMS is from the same age as RES, but it provides a manufacturer and a
+device ID. It is therefore on par with the probing for parallel flash
+chips and specific enough.
+
+The order in which chips should be detected is as follows:
+1. RDID
+2. REMS
+3. RES
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r348 | hailfinger | 2008-11-27 23:48:48 +0100 (Thu, 27 Nov 2008) | 18 lines
+
+Original v2 revision: 3774
+
+The existing check in probe_spi_res() was right for SPI controllers
+which support all commands, but may not exist.
+For controllers which support only a subset of commands, it will fail in
+unexpected ways. Even if a command is supported by the controller, it
+may be unavailable if the controller is locked down.
+
+The new logic checks if RDID could be issued and its return values made
+sense (not 0xff 0xff 0xff). In that case, RES probing is not performed.
+Otherwise, we try RES.
+There is one drawback: If RDID returned unexpected values, we don't
+issue a RES probe. However, in that case we should try to match RDID
+anyway.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: FENG yu ning <fengyuning1984@gmail.com>
+
+------------------------------------------------------------------------
+r347 | stuge | 2008-11-24 21:23:23 +0100 (Mon, 24 Nov 2008) | 9 lines
+
+Original v2 revision: 3769
+
+Add support for 32Mbit SPI flash SST25VF032B. Tested on gigabyte m57sli.
+
+File util/flashrom/flash.h already had correct ID for that part.
+
+Signed-off-by: Tero O Peippola <xeropp@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r346 | hailfinger | 2008-11-18 01:43:14 +0100 (Tue, 18 Nov 2008) | 11 lines
+
+Original v2 revision: 3758
+
+Currently flashrom assumes every vendor BIOS shares our view about which
+SPI opcodes should be placed in which location. Move to a less
+optimistic implementation and actually use the generic SPI read
+functions. They're useful for abstracting exactly this stuff and that
+makes them the preferred choice.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r345 | hailfinger | 2008-11-18 01:41:02 +0100 (Tue, 18 Nov 2008) | 22 lines
+
+Original v2 revision: 3757
+
+Check for failed SPI command execution in flashrom. Although SPI itself
+does not have a mechanism to signal command failure, the SPI host may be
+unable to send a given command over the wire due to security or hardware
+limitations. The current code ignores these mechanisms completely and
+simply assumes almost every command succeeds. Complain if SPI command
+execution fails.
+
+Since locked down Intel chipsets (like the one we had problems with
+earlier) only allow a small subset of commands, find the common subset
+of commands between the chipset and the ROM in the chip erase case. That
+is accomplished by the new spi_chip_erase_60_c7() which can be used for
+chips supporting both 0x60 and 0xc7 chip erase commands.
+
+Both parts of the patch address problems seen in the real world. The
+increased verbosity for the error case will help us diagnose and address
+problems better.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Otherwise: Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r344 | hailfinger | 2008-11-18 01:36:26 +0100 (Tue, 18 Nov 2008) | 24 lines
+
+Original v2 revision: 3756
+
+Implement read support for the following Atmel chips:
+AT25DF021
+AT25DF041A
+AT25DF081
+AT25DF161
+AT25DF321A
+AT25DF641
+AT25F512B
+AT25FS010
+AT25FS040
+AT26DF041
+AT26DF081A
+AT26DF161
+AT26DF161A
+AT26DF321
+AT26F004
+
+I double-checked the data sheets and am confident this will work.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r343 | mraudsepp | 2008-11-17 16:31:56 +0100 (Mon, 17 Nov 2008) | 8 lines
+
+Original v2 revision: 3755
+
+flashrom: SST39VF020 TEST_OK_ PROBE READ ERASE WRITE
+
+Tested fully on a ThinCan DBE61A
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+------------------------------------------------------------------------
+r342 | hailfinger | 2008-11-15 14:55:43 +0100 (Sat, 15 Nov 2008) | 60 lines
+
+Original v2 revision: 3754
+
+The AT25 and AT26 series SPI chips from Atmel are plain EEPROMs.
+The AT45 series SPI chips are DataFlash EEPROMs which means they have
+odd (non-power-of-two) sector sizes, but some of the DataFlash chips can
+be configured or ordered with power-of-two sector sizes.
+
+Add probe support for the following Atmel SPI chips:
+AT25DF021
+AT25DF041A
+AT25DF081
+AT25DF161
+AT25DF321A
+AT25DF641
+AT25F512B
+AT25FS010
+AT25FS040
+AT26DF041
+AT26DF081A
+AT26DF161
+AT26DF161A
+AT26DF321
+AT26F004
+AT45CS1282
+AT45DB011D
+AT45DB021D
+AT45DB041D
+AT45DB081D
+AT45DB161D
+AT45DB321C
+AT45DB321D
+AT45DB642D
+
+Add an explanation why the following chips can't be probed:
+AT45BR3214B
+AT45D011
+AT45D021A
+AT45D041A
+AT45D081A
+AT45D161
+AT45DB011
+AT45DB011B
+AT45DB021A
+AT45DB021B
+AT45DB041A
+AT45DB081A
+AT45DB161
+AT45DB161B
+AT45DB321
+AT45DB321B
+AT45DB642
+
+Add the ID, but no probing function for this chip:
+AT25F512A
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Tested-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
+Tested-by: Andriy Gapon <avg@icyb.net.ua>
+Acked-by: Myles Watson <mylesgw@gmail.com>
+
+------------------------------------------------------------------------
+r341 | stuge | 2008-11-08 02:39:12 +0100 (Sat, 08 Nov 2008) | 9 lines
+
+Original v2 revision: 3736
+
+flashrom: SST39SF040 TEST_OK_ PROBE READ ERASE WRITE
+
+Per report from Mario Rogen. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r340 | hailfinger | 2008-11-05 23:54:36 +0100 (Wed, 05 Nov 2008) | 8 lines
+
+Original v2 revision: 3731
+
+The ST M25P16 chip has been confirmed to work fine for probe, read,
+erase and write by St?\195?\169phan Guilloux.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r339 | hailfinger | 2008-11-04 13:11:12 +0100 (Tue, 04 Nov 2008) | 25 lines
+
+Original v2 revision: 3730
+
+Add support for 8 new chips to flashrom and fix up 2 existing chips
+as well.
+Replace age-old TODO comments with real explanations.
+
+Fixed chips:
+Fujitsu MBM29F400TC (ID definition)
+Macronix MX29F002T (chip name)
+
+New chips:
+Fujitsu MBM29F004BC
+Fujitsu MBM29F004TC
+Fujitsu MBM29F400BC
+Macronix MX25L512
+Macronix MX25L1005
+Macronix MX25L2005
+Macronix MX25L6405
+Macronix MX29F002B
+
+Straight from the data sheets, compile tested only.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r338 | hailfinger | 2008-11-03 01:20:22 +0100 (Mon, 03 Nov 2008) | 8 lines
+
+Original v2 revision: 3723
+
+Dump ICH8/ICH9/ICH10 SPI registers in flashrom.
+This helps a lot if we have to track down configuration weirdnesses.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r337 | hailfinger | 2008-11-03 01:02:11 +0100 (Mon, 03 Nov 2008) | 21 lines
+
+Original v2 revision: 3722
+
+Add additional SPI sector erase and chip erase command functions to
+flashrom. Not all chips support all commands, so allow the implementer
+to select the matching function.
+Fix a layering violation in ICH SPI code to be less bad. Still not
+perfect, but the new code is shorter, more generic and
+architecturally
+more sound.
+
+TODO (in a separate patch):
+- move the generic sector erase code to spi.c
+- decide which erase command to use based on info about the chip
+- create a generic spi_erase_all_sectors function which calls the
+generic sector erase function
+  
+Thanks to Stefan for reviewing and commenting.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r336 | stepan | 2008-11-02 20:51:50 +0100 (Sun, 02 Nov 2008) | 9 lines
+
+Original v2 revision: 3721
+
+Drop nr/opcode_index parameter from run_opcode and search the opmenu for the opcode instead.
+This is slightly slower (ha, ha), but works on boards with a locked opmenu. Tested on ICH7 and works.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r335 | hailfinger | 2008-11-02 15:25:11 +0100 (Sun, 02 Nov 2008) | 10 lines
+
+Original v2 revision: 3717
+
+Add support for the ST M50FW002 chip to flashrom. Identification only,
+erase/write are not implemented.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+tested and
+Acked-by: Elia Yehuda <z4ziggy@gmail.com>
+
+------------------------------------------------------------------------
+r334 | uwe | 2008-10-30 04:10:17 +0100 (Thu, 30 Oct 2008) | 13 lines
+
+Original v2 revision: 3708
+
+Mark two more chips as fully tested (trivial).
+
+ - SST SST39SF010A
+ - Winbond W29C011
+
+Tested by me on actual hardware, all operations.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r333 | stepan | 2008-10-29 23:13:20 +0100 (Wed, 29 Oct 2008) | 10 lines
+
+Original v2 revision: 3707
+
+Flashrom support for some Numonyx parts (M25PE)
+
+using block erase d8 as discussed with Peter Stuge
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r332 | eswierk | 2008-10-29 15:54:36 +0100 (Wed, 29 Oct 2008) | 8 lines
+
+Original v2 revision: 3706
+
+Enable SPI boot flash support on EP80579, which has the ICH7 register set
+(trivial).
+
+Signed-off-by: Ed Swierk <eswierk@aristanetworks.com>
+Acked-by: Ed Swierk <eswierk@aristanetworks.com>
+
+------------------------------------------------------------------------
+r331 | uwe | 2008-10-28 13:00:59 +0100 (Tue, 28 Oct 2008) | 12 lines
+
+Original v2 revision: 3697
+
+Mark Winbond W39V040FA" (512 KB) as fully supported, tested by
+Martin Stecklum <stecky@gmx.net> (both write and erase).
+
+The tests were done on an MSI MS-7065 board, so that's supported now
+too (wiki page will be updated).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r330 | uwe | 2008-10-28 12:50:05 +0100 (Tue, 28 Oct 2008) | 11 lines
+
+Original v2 revision: 3696
+
+Add support for the Intel 82371MX (MPIIX) southbridge (trivial).
+
+Untested, but should work just as well as the other *PIIX* southbridges
+according to the datasheets.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r329 | uwe | 2008-10-26 19:40:42 +0100 (Sun, 26 Oct 2008) | 10 lines
+
+Original v2 revision: 3694
+
+Add support for the Intel 82371FB PIIX and 82371SB (PIIX3) southbridges.
+
+Tested on PIIX3 hardware.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+
+
+------------------------------------------------------------------------
+r328 | uwe | 2008-10-25 20:03:50 +0200 (Sat, 25 Oct 2008) | 8 lines
+
+Original v2 revision: 3693
+
+Add support for the VIA VT82C586A/B chipset, improve documentation.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r327 | uwe | 2008-10-22 00:09:02 +0200 (Wed, 22 Oct 2008) | 10 lines
+
+Original v2 revision: 3682
+
+Reduce serial output, otherwise flashing will fail very often (trivial).
+
+This has been tested on hardware by me.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r326 | uwe | 2008-10-18 23:14:13 +0200 (Sat, 18 Oct 2008) | 8 lines
+
+Original v2 revision: 3669
+
+Coding-style fixes for flashrom, partly indent-aided (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r325 | stuge | 2008-10-18 15:54:30 +0200 (Sat, 18 Oct 2008) | 10 lines
+
+Original v2 revision: 3668
+
+flashrom: Allow the SiS 620 chipset to detect and read at least 256kb chips.
+
+Based on the 5595 datasheet and uniflash 1.40 sources, only looking for info
+about SiS620.
+
+Signed-off-by: Urja Rannikko <urjaman@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r324 | mjones | 2008-10-15 19:50:29 +0200 (Wed, 15 Oct 2008) | 11 lines
+
+Original v2 revision: 3659
+
+SB600 has four write once LPC ROM protect areas. It is not possible to write
+enable that area once the register is set so print a warning.
+
+Signed-off-by: Marc Jones <marcj.jones@amd.com>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r323 | hailfinger | 2008-10-10 22:54:41 +0200 (Fri, 10 Oct 2008) | 10 lines
+
+Original v2 revision: 3648
+
+Add ICH10 support to flashrom.
+
+The ICH9 and ICH10 data sheets are identical regarding FWH/SPI flash
+interfaces, so this just adds the required PCI IDs.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r322 | stuge | 2008-10-10 22:43:17 +0200 (Fri, 10 Oct 2008) | 7 lines
+
+Original v2 revision: 3647
+
+flashrom: Check that a filename was specified also when using force read
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r321 | uwe | 2008-10-07 14:21:12 +0200 (Tue, 07 Oct 2008) | 12 lines
+
+Original v2 revision: 3639
+
+Support for AM29F002(N)B[BT]. Fully tested on AM29F002NBT.
+
+Probing, reading, and erasing use the Jedec-routines,
+whereas writing resort to the recent write_en29f002a(),
+since also these chips use a byte wise algorithm.
+
+Signed-off-by: Mats Erik Andersson <mats.andersson@gisladisker.se>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r320 | stuge | 2008-09-30 06:13:32 +0200 (Tue, 30 Sep 2008) | 14 lines
+
+Original v2 revision: 3619
+
+This patch fixes support for the AT49F002N(T) chip in the flashrom tool.
+
+It replaces the write function to one based on write_byte_program_jedec()
+instead of write_page_write_jedec(), as this part does not support page
+programming.
+I have verified the NT variant to fully work now, and adjusted the test
+status accordingly. The N variant *should* also work with this patch, but
+remains untested.
+
+Signed-off-by: Tim ter Laak <timl@scintilla.utwente.nl>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r319 | stuge | 2008-09-30 06:00:23 +0200 (Tue, 30 Sep 2008) | 9 lines
+
+Original v2 revision: 3618
+
+flashrom: ST M29F040B status TEST_OK_ PROBE READ ERASE WRITE
+
+Per report from Daniel Lindenaar. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r318 | stuge | 2008-09-29 23:21:36 +0200 (Mon, 29 Sep 2008) | 7 lines
+
+Original v2 revision: 3616
+
+flashrom: Fix typo in r3615 (TEST_PREW -> TEST_OK_PREW)
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r317 | uwe | 2008-09-29 20:48:23 +0200 (Mon, 29 Sep 2008) | 10 lines
+
+Original v2 revision: 3615
+
+Mark the SyncMOS S29C51002T as working (trivial).
+
+All operations tested by me on hardware.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r316 | uwe | 2008-09-26 15:19:02 +0200 (Fri, 26 Sep 2008) | 13 lines
+
+Original v2 revision: 3602
+
+Activate proper support for EN29F002(A)(N)[BT].
+
+Fully tested for Probe/Read/Erase/Write on EN29F002NT.
+Jedec subroutines 'probe_jedec()' and 'erase_chip_jedec()'
+are still in use, but a tailored 'write_en29f002a()' is
+needed due to a byte wise writing mechanism for this chip.
+
+Signed-off-by: Mats Erik Andersson <mats.andersson@gisladisker.se>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r315 | stuge | 2008-09-10 11:55:10 +0200 (Wed, 10 Sep 2008) | 9 lines
+
+Original v2 revision: 3570
+
+flashrom: Winbond W49V002A TEST_OK_ PROBE READ ERASE WRITE
+
+Per report from Kevin O'Connor. Thanks Kevin!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r314 | stuge | 2008-09-07 05:14:27 +0200 (Sun, 07 Sep 2008) | 7 lines
+
+Original v2 revision: 3569
+
+flashrom: Debug print actual time base calculated by myusec_calibrate_delay()
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r313 | stuge | 2008-09-04 01:10:05 +0200 (Thu, 04 Sep 2008) | 13 lines
+
+Original v2 revision: 3562
+
+flashrom: Only find "unknown .. SPI chip" if no other chip was found
+
+This removes the false positive matches we've been seeing, and also removes
+the true positive match in case there is more than one flash chip and the 2nd
+or 3rd are unknown - but I think that case is uncommon enough to warrant the
+improvement in the common case. Use flashrom -frc forced read if you have the
+uncommon case, and/or please add the flash chip to the flashchips array.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r312 | stuge | 2008-09-02 02:26:11 +0200 (Tue, 02 Sep 2008) | 9 lines
+
+Original v2 revision: 3557
+
+flashrom: SST49LF016C TEST_OK_ PROBE READ ERASE WRITE
+
+Per test report from Bari Ari. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r311 | stuge | 2008-08-27 23:28:41 +0200 (Wed, 27 Aug 2008) | 9 lines
+
+Original v2 revision: 3541
+
+flashrom: SST25VF016B TEST_OK_ PROBE READ ERASE WRITE
+
+Per test report from Ward.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r310 | hailfinger | 2008-08-20 22:31:41 +0200 (Wed, 20 Aug 2008) | 7 lines
+
+Original v2 revision: 3532
+
+flashrom: Recognize the Intel EP80579 LPC flash interface.
+
+Signed-off-by: Ed Swierk <eswierk@arastra.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r309 | uwe | 2008-08-19 23:51:39 +0200 (Tue, 19 Aug 2008) | 9 lines
+
+Original v2 revision: 3528
+
+Add support for MSI KT4V to flashrom. The KT4V is autodetected and supports
+the KT3 Ultra 2 with "-m msi:kt4v" (but is not autodetected, yet).
+
+Signed-off-by: Sean Nelson <snelson@nmt.edu>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r308 | segher | 2008-08-12 13:58:00 +0200 (Tue, 12 Aug 2008) | 13 lines
+
+Original v2 revision: 3502
+
+flashrom: Fix error -EINVAL on mmap()
+
+Don't calculate "flash_baseaddr" until the final value of "size"
+is known, otherwise we end up trying to map a page right after
+the end of memory.
+
+Fixes #112.
+
+Signed-off-by: Segher Boessenkool <segher@kernel.crashing.org>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r307 | stuge | 2008-08-08 12:55:57 +0200 (Fri, 08 Aug 2008) | 9 lines
+
+Original v2 revision: 3485
+
+flashrom: ST M50FW040 TEST_OK PROBE READ ERASE WRITE
+
+Per test report from Marcel Konrad. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r306 | stepan | 2008-08-02 17:13:58 +0200 (Sat, 02 Aug 2008) | 8 lines
+
+Original v2 revision: 3464
+
+update copyright year (trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r305 | stepan | 2008-08-02 16:58:49 +0200 (Sat, 02 Aug 2008) | 8 lines
+
+Original v2 revision: 3462
+
+tested another intel chip (trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r304 | stuge | 2008-07-21 19:48:40 +0200 (Mon, 21 Jul 2008) | 15 lines
+
+Original v2 revision: 3431
+
+flashrom: Winbond W39V040C and MSI K8T Neo2-F
+
+W39V040C does standard JEDEC commands except chip erase so add a small driver.
+probe_w39v040c() prints the block lock pin status when a chip is found.
+
+The Neo2 board enable matches on 8237-internal IDE and onboard NIC PCI IDs.
+
+Many thanks to Daniel McLellan for testing all of this on hardware!
+Build tested by Uwe.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r303 | hailfinger | 2008-07-11 02:06:38 +0200 (Fri, 11 Jul 2008) | 8 lines
+
+Original v2 revision: 3420
+
+Fix and clean up coreboot image detection heuristic.
+Additional compile fix for NetBSD.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r302 | stuge | 2008-07-07 08:38:51 +0200 (Mon, 07 Jul 2008) | 17 lines
+
+Original v2 revision: 3418
+
+flashrom: Trivial SPI cleanups
+
+While writing a new SPI driver I fixed some things in the SPI code:
+All calls to spi_command() had unneccessary #define duplications, and in some
+cases the read count define could theoretically become harmful because NULL was
+passed for the read buffer. Avoid a crash, should someone change the #defines.
+
+I also noticed that the only caller of spi_page_program() was the it87 driver,
+and spi_page_program() could only call back into the it87 driver. Removed the
+function for easier-to-follow code and made it8716f_spi_page_program() static.
+The ichspi driver's static page functions are already static.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r301 | stuge | 2008-07-07 07:14:06 +0200 (Mon, 07 Jul 2008) | 7 lines
+
+Original v2 revision: 3417
+
+flashrom: Trivial indent fix in ichspi.c
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r300 | hailfinger | 2008-07-07 01:04:01 +0200 (Mon, 07 Jul 2008) | 11 lines
+
+Original v2 revision: 3416
+
+r3415 removed symbolic constants for device IDs by accident.
+flash.h is a database of known IDs, whereas flashchips.c is a database
+of chips for which support has been implemented. Keep it that way.
+
+Trivial.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r299 | stuge | 2008-07-06 19:35:30 +0200 (Sun, 06 Jul 2008) | 19 lines
+
+Original v2 revision: 3415
+
+flashrom: Add AMIC A29002
+
+This patch adds support to the AMIC A29002 chip in its top and bottom
+configuration to flashrom. Additionally, the alphabetic order of the
+AMIC chips was fixed.
+
+The datasheet is at <http://www.amictechnology.com/pdf/A29002.pdf>.
+
+A29002T PREW functionality was tested and works.
+
+This flash chip has asymmetric sector layout so it is important to use the
+mx29f002 driver, which does chip erase before writing, rather than am29f040b,
+which uses sector erase.
+
+Signed-off-by: Andreas Thienemann <andreas@bawue.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r298 | stepan | 2008-07-05 11:48:30 +0200 (Sat, 05 Jul 2008) | 8 lines
+
+Original v2 revision: 3414
+
+Adding support for flashing system with Nvidia MCP67
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r297 | stuge | 2008-07-05 06:12:37 +0200 (Sat, 05 Jul 2008) | 10 lines
+
+Original v2 revision: 3413
+
+flashrom: Add PCI IDs for EPIA-CN
+
+Uses the 0.0 Host bridge CN700/VN800/P4M800CE/Pro and 11.0 ISA bridge devices
+with their 1106:aa08 subsystem id:s for autodetection.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r296 | uwe | 2008-07-03 21:26:44 +0200 (Thu, 03 Jul 2008) | 8 lines
+
+Original v2 revision: 3412
+
+Minor cosmetics, e.g. make stuff fit in 80 chars/line etc. (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r295 | hailfinger | 2008-07-03 21:08:52 +0200 (Thu, 03 Jul 2008) | 8 lines
+
+Original v2 revision: 3411
+
+Mark SST49LF040B as tested.
+Thanks to Paul Seidler and Ward Vandewege for testing.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r294 | uwe | 2008-07-03 20:58:58 +0200 (Thu, 03 Jul 2008) | 8 lines
+
+Original v2 revision: 3410
+
+Mark the SST SST49LF040 as OK (tested by me), all operations (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r293 | stuge | 2008-07-03 18:54:05 +0200 (Thu, 03 Jul 2008) | 9 lines
+
+Original v2 revision: 3409
+
+flashrom: Winbond W25x80 TEST_OK PROBE READ ERASE WRITE
+
+Per test report from Bj?\195?\182rn Gerhart. Thanks!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r292 | hailfinger | 2008-07-03 16:40:06 +0200 (Thu, 03 Jul 2008) | 9 lines
+
+Original v2 revision: 3408
+
+Improve coreboot image detection heuristic in flashrom. It's not
+absolutely perfect, but the likelihood of this check to fail is
+0.000000000000000000000000013 (1.3*10^-26) which is good enough for me.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de> 
+
+------------------------------------------------------------------------
+r291 | stuge | 2008-07-02 19:15:47 +0200 (Wed, 02 Jul 2008) | 7 lines
+
+Original v2 revision: 3407
+
+flashrom: probe_flash() cleanup for better code readability
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r290 | stepan | 2008-07-02 15:33:09 +0200 (Wed, 02 Jul 2008) | 12 lines
+
+Original v2 revision: 3406
+
+set w39v080fa to fully supported. I'm am flashing this chip several times a
+day.
+Also enable unlocking which is only needed when running coreboot, that slipped
+in the original commit and through the original review ;-) So it must be
+trivial enough.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r289 | stuge | 2008-07-02 05:07:46 +0200 (Wed, 02 Jul 2008) | 9 lines
+
+Original v2 revision: 3405
+
+flashrom: Update to TEST_OK for Winbond W39V040FA PROBE READ
+
+Thanks to Jake for the test report!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r288 | stuge | 2008-07-02 05:03:58 +0200 (Wed, 02 Jul 2008) | 7 lines
+
+Original v2 revision: 3404
+
+flashrom: Don't rm *~ in make clean, who knows what files that could be
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r287 | stuge | 2008-07-02 02:59:29 +0200 (Wed, 02 Jul 2008) | 9 lines
+
+Original v2 revision: 3403
+
+flashrom: Unknown vendor:board message can be triggered by -m too
+
+Thanks to Stefan for pointing this one out.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r286 | stuge | 2008-07-02 02:47:30 +0200 (Wed, 02 Jul 2008) | 10 lines
+
+Original v2 revision: 3402
+
+flashrom: Case insensitive matching of vendor:board strings in coreboot table
+
+Needed at least for GIGABYTE:m57sli in coreboot to match gigabyte:m57sli in
+flashrom.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r285 | stepan | 2008-07-01 01:45:22 +0200 (Tue, 01 Jul 2008) | 18 lines
+
+Original v2 revision: 3401
+
+First attempt to clean up SPI probing and create a common
+construct: the flash bus.
+
+At some point the flash bus will be part of struct flashchip.
+
+Pardon me for pushing this in, but I think it is important to beware of further
+decay and it will improve things for other developers in the short run.
+
+Carl-Daniel, I will consider your suggestions in another patch. I want to keep
+things from getting too much for now. The patch includes Rudolf's VIA SPI
+changes though.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r284 | ruik | 2008-06-30 23:48:54 +0200 (Mon, 30 Jun 2008) | 8 lines
+
+Original v2 revision: 3400
+
+Mine AMIC flash chip needs 4 bytes RDID. This enables to use the new probing code.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r283 | ruik | 2008-06-30 23:45:17 +0200 (Mon, 30 Jun 2008) | 8 lines
+
+Original v2 revision: 3399
+
+Mine AMIC flash chip needs 4 bytes RDID. Following patch adds support for that.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r282 | ruik | 2008-06-30 23:38:30 +0200 (Mon, 30 Jun 2008) | 9 lines
+
+Original v2 revision: 3398
+
+This patch adds support for VIA SPI controller on VT8237S. It is similar with
+few documented exceptions to ICH7 SPI controller.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r281 | hailfinger | 2008-06-29 12:57:13 +0200 (Sun, 29 Jun 2008) | 7 lines
+
+Original v2 revision: 3397
+
+Add a debug marker after ICH SPI opcode programming.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r280 | stuge | 2008-06-29 03:30:41 +0200 (Sun, 29 Jun 2008) | 12 lines
+
+Original v2 revision: 3395
+
+flashrom: Fix ICH7 non-SPI that broke in r3393
+
+r3393 assumed that ICH7 always used SPI. This patch resets ich7_detected back
+to 0 when BOOT BIOS Straps indicate something else than SPI.
+
+Also fixes a build error in ichspi.c with gcc 4.2.2.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r279 | hailfinger | 2008-06-29 01:02:22 +0200 (Sun, 29 Jun 2008) | 7 lines
+
+Original v2 revision: 3394
+
+Use symbolic constants for PCI subsystem probing in flashrom.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r278 | stepan | 2008-06-27 18:28:34 +0200 (Fri, 27 Jun 2008) | 11 lines
+
+Original v2 revision: 3393
+
+* ICH7 SPI support
+* fix some variable names in ichspi.c (Offset -> offset)
+* Dump ICH7 SPI bar with -V
+* Improve error message in case IOPL goes wrong. (It might not even be an IOPL)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r277 | stepan | 2008-06-27 17:18:20 +0200 (Fri, 27 Jun 2008) | 6 lines
+
+Original v2 revision: 3392
+
+indent according to development guidelines (trivial)
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r276 | uwe | 2008-06-26 13:57:27 +0200 (Thu, 26 Jun 2008) | 8 lines
+
+Original v2 revision: 3390
+
+Winbond W39V080FA: Probe and Read are OK.
+
+Signed-off-by: Jens K?\195?\188hnel <coreboot@jens.kuehnel.org>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r275 | stuge | 2008-06-24 10:18:13 +0200 (Tue, 24 Jun 2008) | 9 lines
+
+Original v2 revision: 3389
+
+flashrom: Test status OK for ST M50FW040 PROBE READ
+
+Per test report from Alex Perez. Thanks Alex!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r274 | stuge | 2008-06-24 06:17:14 +0200 (Tue, 24 Jun 2008) | 9 lines
+
+Original v2 revision: 3388
+
+flashrom: Test status OK for Macronix MX25L8005 PROBE READ ERASE WRITE
+
+Per test report from Andrew Paprocki. Thanks Andrew!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r273 | stuge | 2008-06-24 04:09:09 +0200 (Tue, 24 Jun 2008) | 10 lines
+
+Original v2 revision: 3387
+
+flashrom: Increase delay in probe_jedec() after Product ID Entry to 10ms
+
+We should follow data sheet timing, even if chips have been tested to answer
+faster in the field.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r272 | stuge | 2008-06-24 03:22:03 +0200 (Tue, 24 Jun 2008) | 16 lines
+
+Original v2 revision: 3386
+
+flashrom: Slight restructure of SPI probe_ functions
+
+Preparation for a probe optimization patch. This patch does not change any
+functionality. spi_probe_rdid was tested to still work on my M57SLI rev 2.
+
+The idea is to have error checks return error immediately when something
+fails, rather than having code inside an if block where the condition
+tests for success.
+
+This means: Less indentation, more clear what the code is checking.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r271 | uwe | 2008-06-22 20:50:25 +0200 (Sun, 22 Jun 2008) | 8 lines
+
+Original v2 revision: 3385
+
+Some flashrom documentation fixes, and removal of duplicated info (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r270 | stuge | 2008-06-22 19:54:03 +0200 (Sun, 22 Jun 2008) | 7 lines
+
+Original v2 revision: 3384
+
+flashrom: A few changes were committed before the DoC remove, update README.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r269 | stepan | 2008-06-22 19:06:41 +0200 (Sun, 22 Jun 2008) | 15 lines
+
+Original v2 revision: 3382
+
+flashrom: Remove dead M-Systems Disk on Chip code
+
+DOC support has been disabled by default for many years. The write function
+does nothing but print text. It has a call to write_page_md2802() commented
+out, but that function does not exist. This is dead code with ugly #ifdefs.
+
+Updates README to reflect that there was a time when there was code, but it
+didn't work. Removes M-Systems #defines and also includes svn rm msys_doc.*
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r268 | stuge | 2008-06-22 04:04:49 +0200 (Sun, 22 Jun 2008) | 9 lines
+
+Original v2 revision: 3379
+
+flashrom: Update test status to TEST_OK_PREW for ST M50FLW080A and SST49LF008A
+
+Many thanks to Julio Cesar Costa for the test report!
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r267 | stuge | 2008-06-22 04:00:39 +0200 (Sun, 22 Jun 2008) | 7 lines
+
+Original v2 revision: 3378
+
+flashrom: Some Makefile cleaning
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r266 | stuge | 2008-06-21 06:39:17 +0200 (Sat, 21 Jun 2008) | 7 lines
+
+Original v2 revision: 3377
+
+flashrom: Fix OBJS in Makefile to compile stm50flw0x0x.c like the others
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r265 | stuge | 2008-06-21 06:23:10 +0200 (Sat, 21 Jun 2008) | 7 lines
+
+Original v2 revision: 3376
+
+flashrom: Uppercase AMIC since that's what they write in datasheets.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r264 | stuge | 2008-06-21 03:02:20 +0200 (Sat, 21 Jun 2008) | 7 lines
+
+Original v2 revision: 3375
+
+flashrom: Update comment to match delay change in probe_jedec() r3373
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r263 | stuge | 2008-06-21 02:21:22 +0200 (Sat, 21 Jun 2008) | 9 lines
+
+Original v2 revision: 3374
+
+flashrom: Update test status for Atmel AT29C020 and SST29EE010
+
+Thanks to Urja Rannikko for reporting test results with these flash chips.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r262 | stuge | 2008-06-21 02:19:52 +0200 (Sat, 21 Jun 2008) | 10 lines
+
+Original v2 revision: 3373
+
+flashrom: Increase delay in probe_jedec() to 2ms to reliably detect AT29C020
+
+Run time is increased a few 100ms but this is needed for reliability.
+I consider this trivial.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r261 | stuge | 2008-06-20 04:58:42 +0200 (Fri, 20 Jun 2008) | 7 lines
+
+Original v2 revision: 3372
+
+flashrom: Show expected and read byte on verify failure. Trivial.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r260 | stuge | 2008-06-18 15:36:34 +0200 (Wed, 18 Jun 2008) | 24 lines
+
+Original v2 revision: 3368
+
+flashrom: Add support for AMIC Technology A49LF040A and do not probe W29EE011 anymore
+
+Jens sent the first patch that added A49LF040A to flash.h and flashchips.c
+using _jedec and _49lf040 functions.
+
+An issue was found with probe_w29ee011() for the Winbond W29EE011, which
+caused the A49LF040A to no longer respond to any commands.
+
+Ward made a patch to disable probing by default for the W29EE011 following
+some discussion. Using -c W29EE011 will make flashrom probe for the chip.
+
+Peter did some more datasheet diving and found that the Pm49FL00x functions
+suited this chip quite well because of the block locking registers in
+A49LF040A, and finally tested PROBE READ ERASE WRITE to work on ALIX.3c3.
+
+Ward confirmed that this works on alix.2c3 too.
+
+Signed-off-by: Jens Kuehnel <coreboot@jens.kuehnel.org>
+Signed-off-by: Ward Vandewege <ward@gnu.org>
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r259 | stuge | 2008-06-18 04:08:40 +0200 (Wed, 18 Jun 2008) | 19 lines
+
+Original v2 revision: 3367
+
+flashrom: Force read unknown flash chips
+
+When flash chip detection fails, it is still useful and possible to read the
+flash chip contents. If no flash chip is found in normal probes and the
+-f -r -c CHIPNAME options are given, a successful probe for the specified
+chip is forced, and then flashrom reads the flash chip using either the read
+function for the specified chip, or if there is none, a simple memcpy().
+
+The patch also moves the global variable int force in flashrom.c into main()
+and passes it as a parameter to layout.c:show_id(), which was the only other
+function that used the variable. This is needed to avoid confusion with the
+new parameter int force which is added to flashrom.c:probe_flash() and used
+to force probe success for the chip named in char *chip_to_probe.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r258 | stuge | 2008-06-13 03:39:45 +0200 (Fri, 13 Jun 2008) | 10 lines
+
+Original v2 revision: 3366
+
+flashrom: Board enable and autodetection for GIGABYTE GA-7VT600
+
+Uses the VT8237 ISA bridge with mainboard subsystem ID and Realtek 8139 with
+mainboard subsystem ID for board detection.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Lyos Gemini Norezel <lyos.gemininorezel@gmail.com>
+
+------------------------------------------------------------------------
+r257 | stuge | 2008-06-11 04:24:15 +0200 (Wed, 11 Jun 2008) | 9 lines
+
+Original v2 revision: 3365
+
+flashrom: Add support for Amic Technology A29040B flash chip.
+
+PROBE READ tested by Lyos Gemini Norezel on BioStar P4M80-M4.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Lyos Gemini Norezel <lyos.gemininorezel@gmail.com>
+
+------------------------------------------------------------------------
+r256 | stuge | 2008-06-11 04:22:42 +0200 (Wed, 11 Jun 2008) | 13 lines
+
+Original v2 revision: 3364
+
+flashrom: Board enable and autodetection for BioStar P4M80-M4.
+
+Thanks to Reinder for clean room reverse engineering and data sheet diving!
+
+This board is autodetected because there are some good BioStar subsystem IDs.
+Matching uses onboard VT6420 SATA RAID with subsystem BioStar 3206 and
+onboard UniChrome Pro IGP graphics with subsystem BioStar 1202.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Lyos Gemini Norezel <lyos.gemininorezel@gmail.com>
+
+------------------------------------------------------------------------
+r255 | stuge | 2008-06-03 02:22:00 +0200 (Tue, 03 Jun 2008) | 14 lines
+
+Original v2 revision: 3360
+
+Ward writes:
+
+SST SST49LF160C is confirmed to work for PROBE READ ERASE WRITE, at least on
+2 MCP55-based boards (gigabyte m57sli v1 and supermicro h8dmr).
+
+On the m57sli board, it only works > 512K when booted into coreboot; the
+proprietary bios seems to do something weird where it locks rom access down
+to the first 512K of the chip.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r254 | mraudsepp | 2008-05-28 01:51:55 +0200 (Wed, 28 May 2008) | 7 lines
+
+Original v2 revision: 3358
+
+Revert r3357 and fix it as intended to (forgotten header commit instead of typo)
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+
+------------------------------------------------------------------------
+r253 | mraudsepp | 2008-05-28 00:20:30 +0200 (Wed, 28 May 2008) | 7 lines
+
+Original v2 revision: 3357
+
+Fix typo introduced in r3356 that breaks build (trivial).
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+
+------------------------------------------------------------------------
+r252 | stuge | 2008-05-27 22:54:09 +0200 (Tue, 27 May 2008) | 13 lines
+
+Original v2 revision: 3356
+
+flashrom: MX25L4005, S25FL016A, W39V040B, W39V080A, SST49LF008A tests.
+
+I have tested MX25L4005, S25FL016A and W39V080A myself.
+
+Thanks also to the following testers:
+SST49LF008A Bernhard M. Wiedemann
+W39V040B Dan Lenski
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r251 | mraudsepp | 2008-05-27 11:10:52 +0200 (Tue, 27 May 2008) | 9 lines
+
+Original v2 revision: 3350
+
+Mark SST49LF004A/B as tested (trivial).
+
+Tested by me on actual hardware (all operations) - Artec Group DBE62 with SST 49LF004B
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+
+------------------------------------------------------------------------
+r250 | uwe | 2008-05-27 01:12:25 +0200 (Tue, 27 May 2008) | 16 lines
+
+Original v2 revision: 3349
+
+Mark the following chips as tested (trivial).
+
+  - AMD Am29F040B
+  - SST SST39SF020A
+  - Winbond W29C020C
+  - Winbond W29EE011
+  - Winbond W49F002U
+
+All of them tested by me on actual hardware (all operations).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r249 | uwe | 2008-05-23 00:47:04 +0200 (Fri, 23 May 2008) | 12 lines
+
+Original v2 revision: 3348
+
+A bunch of cosmetic improvements (trivial).
+
+ - Fix typos and inconsistencies.
+ - Drop duplicate line which tells us the chip name twice.
+ - Also print the chip vendor, not only the name.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r248 | uwe | 2008-05-22 23:26:42 +0200 (Thu, 22 May 2008) | 8 lines
+
+Original v2 revision: 3347
+
+Mark more chips as tested (all operations), tested on ASUS P4B266 (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r247 | uwe | 2008-05-22 23:19:38 +0200 (Thu, 22 May 2008) | 16 lines
+
+Original v2 revision: 3346
+
+Add support for the ASUS P4B266 board.
+
+Tested on actual hardware.
+
+This patch add an ich_gpio_raise() function which can be re-used by other
+board-specific funtions which need to raise GPIOs on ICHx southbridges.
+
+This also fixes bug #7, see http://tracker.coreboot.org/trac/coreboot/ticket/7,
+as it turned out the ICH2 (and other ICHx) code works fine.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r246 | hailfinger | 2008-05-22 15:42:23 +0200 (Thu, 22 May 2008) | 7 lines
+
+Original v2 revision: 3345
+
+Add support for Amic A25L40P SPI flash.
+
+Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r245 | hailfinger | 2008-05-22 15:22:45 +0200 (Thu, 22 May 2008) | 11 lines
+
+Original v2 revision: 3344
+
+Changes to make flashrom compile (and work) on FreeBSD.
+This patch addresses different argument order of outX() calls,
+FreeBSD-specific headers, difference in certain type names and system
+interface names, and also FreeBSD-specific way of gaining IO port
+access.
+
+Signed-off-by: Andriy Gapon <avg@icyb.net.ua>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r244 | stuge | 2008-05-21 09:10:15 +0200 (Wed, 21 May 2008) | 7 lines
+
+Original v2 revision: 3341
+
+Myles reported SST49LF080A status -> TESTED_PREW
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r243 | stuge | 2008-05-17 03:08:58 +0200 (Sat, 17 May 2008) | 18 lines
+
+Original v2 revision: 3332
+
+flashrom: Support Pm49FL004/2 Block Locking Registers
+
+The PMC chips understand both LPC and FWH flash commands. When in FWH mode
+(MSR_DIVIL_BALL_OPT(0x51400015) = 0x00000f7d on 5536 boards) the Block
+Locking Registers by default lock the flash chip for write and erase - in
+addition to any chipset write protection.
+
+This patch adds unlock operations before Pm49FL004/2 write and erase, and
+it includes an svn mv pm49fl004.c pm49fl00x.c
+
+Thanks go to Nikolay for this patch.
+
+Signed-off-by: Nikolay Petukhov <nikolay.petukhov@gmail.com>
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Bari Ari <bari@onelabs.com>
+
+------------------------------------------------------------------------
+r242 | hailfinger | 2008-05-16 23:11:53 +0200 (Fri, 16 May 2008) | 13 lines
+
+Original v2 revision: 3331
+
+I looked at the datasheet and erase_sector_39sf020() is totally and
+completely wrong. It was a straight cut'n'paste from SST 28SF040 code
+and the person doing the cut'n'paste didn't even bother to check the
+data sheet. The SST 39SF020 is completely incompatible with the 28SF040.
+
+No need for replacement. According to the data sheet, standard JEDEC
+commands will work and we have those commands in the tree already.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Joseph Smith <joe@settoplinux.org>
+
+------------------------------------------------------------------------
+r241 | hailfinger | 2008-05-16 16:39:39 +0200 (Fri, 16 May 2008) | 8 lines
+
+Original v2 revision: 3327
+
+ICH8 and ICH9 have an almost identical SPI interface, only the location
+of the SPIBAR differs. Add ICH8 support to the ICH9 code.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r240 | hailfinger | 2008-05-16 15:00:28 +0200 (Fri, 16 May 2008) | 8 lines
+
+Original v2 revision: 3326
+
+Add support for the Atmel AT25DF321 SPI flash (tested).
+Change ST M25P32 status to tested.
+
+Signed-off-by: Dominik Geyer <dominik.geyer@kontron.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r239 | hailfinger | 2008-05-16 14:55:55 +0200 (Fri, 16 May 2008) | 8 lines
+
+Original v2 revision: 3325
+
+Add support for SPI chips on ICH9. This is done by using the generic SPI
+interface.
+
+Signed-off-by: Dominik Geyer <dominik.geyer@kontron.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r238 | hailfinger | 2008-05-16 02:19:52 +0200 (Fri, 16 May 2008) | 8 lines
+
+Original v2 revision: 3324
+
+Enable IT8716F LPC-to-SPI write cycle translation in flashrom if the
+IT8716F decodes any address to the attached SPI ROM.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r237 | hailfinger | 2008-05-16 00:32:08 +0200 (Fri, 16 May 2008) | 7 lines
+
+Original v2 revision: 3323
+
+Print detailed status register information for SST25VF series flash.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r236 | hailfinger | 2008-05-15 05:24:43 +0200 (Thu, 15 May 2008) | 9 lines
+
+Original v2 revision: 3321
+
+Lots of new SST flash chip IDs. Only a subset has been added to
+flashchips.c, but the IDs in flash.h will make lookups easier if anybody
+wants to add support for them.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r235 | hailfinger | 2008-05-15 05:19:49 +0200 (Thu, 15 May 2008) | 14 lines
+
+Original v2 revision: 3320
+
+Add support for the JEDEC RES (Read Electronic Signature and Resume from
+Powerdown) SPI command to flashrom to identify older SPI chips which
+can't handle JEDEC RDID. Since RES gives a one-byte identifier which is
+shared among many different vendors and even different sizes, we want to
+match RES as a last resort if RDID returns 0xff 0xff 0xff.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+This is a heavily reworked version of a patch by Fredrik Tolf, which was
+Signed-off-by: Fredrik Tolf <fredrik@dolda2000.com>
+
+------------------------------------------------------------------------
+r234 | hailfinger | 2008-05-14 16:51:22 +0200 (Wed, 14 May 2008) | 7 lines
+
+Original v2 revision: 3314
+
+Add more infrastructure for flashrom ICH9 support.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r233 | hailfinger | 2008-05-14 14:22:38 +0200 (Wed, 14 May 2008) | 7 lines
+
+Original v2 revision: 3310
+
+Add the Intel 6300ESB as known chipset to the chipset struct enables.
+
+Signed-off-by: Claus Gindhart <claus.gindhart@kontron.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r232 | hailfinger | 2008-05-14 14:09:31 +0200 (Wed, 14 May 2008) | 7 lines
+
+Original v2 revision: 3309
+
+Fix crash caused by division by zero for unknown flash chips.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r231 | hailfinger | 2008-05-14 14:03:06 +0200 (Wed, 14 May 2008) | 11 lines
+
+Original v2 revision: 3308
+
+Check the JEDEC vendor ID for correct parity. Flash chips which can be
+detected by JEDEC probe routines all have vendor IDs with correct
+parity. Use a parity check as additional hint whether a vendor ID makes
+sense.
+Note: Device IDs have no parity requirements whatsoever.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r230 | hailfinger | 2008-05-14 06:27:02 +0200 (Wed, 14 May 2008) | 8 lines
+
+Original v2 revision: 3306
+
+Add lots of ATMEL SPI flash chips to flash.h.
+Add a few flashchips already mentioned in flash.h to flashchips.c
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r229 | hailfinger | 2008-05-14 01:03:12 +0200 (Wed, 14 May 2008) | 9 lines
+
+Original v2 revision: 3305
+
+flashrom: Move all IT87xx specific SPI routines from spi.c to a separate
+file it87spi.c.
+No behavioural changes, but greatly improved SPI abstraction.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r228 | hailfinger | 2008-05-13 16:58:23 +0200 (Tue, 13 May 2008) | 8 lines
+
+Original v2 revision: 3302
+
+flashrom: Move the SPI #defines from spi.c to spi.h
+This patch has no code changes.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r227 | hailfinger | 2008-05-13 16:01:22 +0200 (Tue, 13 May 2008) | 8 lines
+
+Original v2 revision: 3301
+
+Change the SPI parts of flashrom to prepare for a merge of
+ICH9 SPI support. In theory, this patch has no behaviour changes.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r226 | hailfinger | 2008-05-12 23:19:53 +0200 (Mon, 12 May 2008) | 9 lines
+
+Original v2 revision: 3300
+
+MX25L3205 and W25x40 have been confirmed to probe/read/erase/write OK
+by Harald Gutmann.
+SST39VF040 has been confirmed to probe OK by misi e.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r225 | hailfinger | 2008-05-12 16:25:31 +0200 (Mon, 12 May 2008) | 9 lines
+
+Original v2 revision: 3299
+
+Add SST39VF512, SST39VF010, SST39VF040 support to flashrom. The SST39LF
+series has the same IDs.
+Add short AMIC vendor ID to flashrom.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r224 | hailfinger | 2008-05-11 01:40:51 +0200 (Sun, 11 May 2008) | 12 lines
+
+Original v2 revision: 3296
+
+Improve flashrom SPI abstraction, second step.
+This paves the way to have a fully generic generic_spi_command without
+knowledge about any SPI controller.
+
+The third step would be calling SPI controller functions via a function
+pointer.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r223 | stuge | 2008-05-11 01:07:52 +0200 (Sun, 11 May 2008) | 9 lines
+
+Original v2 revision: 3295
+
+flashrom: Rename generic_spi_*() functions to spi_*()
+
+This is a very early step toward cleaning up SPI code in flashrom.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r222 | stuge | 2008-05-08 02:31:44 +0200 (Thu, 08 May 2008) | 19 lines
+
+Original v2 revision: 3291
+
+flashrom: Probe for up to 3 flash chips.
+
+Currently there is an ongoing technology migration from LPC/FWH to SPI chips.
+For this reason some boards have multiple chips of different technologies
+onboard. This patch makes flashrom probe for up to 3 chips and if more than
+one chip is found flashrom exits, asking the user to specify -c.
+
+[root@localhost src]# ./flashrom
+...
+Multiple flash chips were detected: SST49LF008A M25P16@ICH9
+Please specify which chip to use with the -c <chipname> option.
+[root@localhost src]# 
+
+Signed-off-by: Claus Gindhart <claus.gindhart@kontron.com>
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Claus Gindhart <claus.gindhart@kontron.com>
+
+------------------------------------------------------------------------
+r221 | stuge | 2008-05-03 06:34:37 +0200 (Sat, 03 May 2008) | 15 lines
+
+Original v2 revision: 3277
+
+flashrom: Add a tested bitmap field to the flash chip table.
+
+Two bits indicate OK and BAD for each operation PROBE READ ERASE WRITE.
+8 bits out of 32 are in use now. No bits set means nothing has been tested.
+For chips with at least one operation that is not tested or not working, the
+user is asked to email a report to a special email adress so that the table
+can be updated.
+
+All chips are TEST_UNTESTED for now.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r220 | stepan | 2008-04-29 15:46:38 +0200 (Tue, 29 Apr 2008) | 8 lines
+
+Original v2 revision: 3275
+
+flashrom: Enable ROM decode range to 1MB for vt8237r
+
+Signed-off-by: Bari Ari <bari@onelabs.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r219 | stepan | 2008-04-28 19:51:09 +0200 (Mon, 28 Apr 2008) | 17 lines
+
+Original v2 revision: 3274
+
+The generic jedec.c does not work for the ST M50FLW flash
+devices, because they need an unlock command first.
+For this reason, ST M50FLW support is moved to a
+new HW support module, because any change in jedec.c
+would bear the risk to cause problems with the already
+supported devices.
+
+It's already tested with ST M50FLW080A; the other
+chips of this family i dont have available, so i couldnt
+test it.
+
+Signed-off-by: Claus Gindhart <claus.gindhart@kontron.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r218 | stuge | 2008-04-28 16:47:30 +0200 (Mon, 28 Apr 2008) | 8 lines
+
+Original v2 revision: 3273
+
+flashrom: Handle NULL probe, erase and write function pointers in the
+flashchips table. The read pointer was already checked properly.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r217 | stepan | 2008-04-24 11:07:57 +0200 (Thu, 24 Apr 2008) | 14 lines
+
+Original v2 revision: 3260
+
+Flash pages, which where excluded from updating using the exclude or the
+layout option, as well as areas, whose flash contents already contain the
+desired data, will be skipped.
+These ensures absolute data security of critical areas (BIOS boot block), 
+e.g. against a sudden power off or a CPU hangup during flashing. As a
+nice side effect, it speeds up the flash process, if the BIOS to be flashed
+is very similar to the version in flash. 
+
+Signed-off-by: Claus Gindhart <claus.gindhart@kontron.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r216 | eswierk | 2008-04-08 00:33:33 +0200 (Tue, 08 Apr 2008) | 8 lines
+
+Original v2 revision: 3221
+
+ST M50FW016 and ST M50FW040 support the 82802ab command set, not jedec.
+
+Signed-off-by: Ed Swierk <eswierk@arastra.com>
+Acked-by: Joseph Smith <joe@smittys.pointclark.net>
+
+
+------------------------------------------------------------------------
+r215 | hailfinger | 2008-03-18 01:54:10 +0100 (Tue, 18 Mar 2008) | 7 lines
+
+Original v2 revision: 3167
+
+Add ICH9 detection to flashrom. Straight from the datasheet, untested.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r214 | stepan | 2008-03-18 01:36:18 +0100 (Tue, 18 Mar 2008) | 11 lines
+
+Original v2 revision: 3166
+
+oops. forgot to add the file.
+
+Support for the Winbond W39V080FA series of chips.
+Support for flashing on the Kontron 986LCD-M board.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r213 | stepan | 2008-03-17 23:59:40 +0100 (Mon, 17 Mar 2008) | 9 lines
+
+Original v2 revision: 3165
+
+Support for the Winbond W39V080FA series of chips.
+Support for flashing on the Kontron 986LCD-M board.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r212 | stepan | 2008-03-16 20:44:13 +0100 (Sun, 16 Mar 2008) | 9 lines
+
+Original v2 revision: 3153
+
+check whether SST FWH chip was successfully erased on flashchip -E, too
+(trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r211 | uwe | 2008-03-16 03:06:25 +0100 (Sun, 16 Mar 2008) | 8 lines
+
+Original v2 revision: 3152
+
+Sort list of flash chips alphabetically, add comment (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r210 | stepan | 2008-03-16 00:41:19 +0100 (Sun, 16 Mar 2008) | 7 lines
+
+Original v2 revision: 3151
+
+remove nasty warning that happened due to our vendor detection
+mechanism.
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r209 | uwe | 2008-03-15 00:55:58 +0100 (Sat, 15 Mar 2008) | 8 lines
+
+Original v2 revision: 3146
+
+Re-add code erroneously removed in r3140.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r208 | linux_junkie | 2008-03-15 00:32:03 +0100 (Sat, 15 Mar 2008) | 6 lines
+
+Original v2 revision: 3145
+
+Changes M50FW080 to use 82802ab.c instead of jedec.c. This fixes the problem of not being able to erase the chip.
+
+Signed-off-by: Joseph Smith <joe@smittys.pointclark.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+------------------------------------------------------------------------
+r207 | hailfinger | 2008-03-14 18:20:59 +0100 (Fri, 14 Mar 2008) | 13 lines
+
+Original v2 revision: 3144
+
+Prepare for ICH7/ICH8 SPI support by adding some debugging for all
+ICH* chipsets. Functionality (except printing) should be unchanged.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+Ward says:
+This code detects the ICH8 chipset on my laptop, and it appears to use
+SPI.
+
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r206 | uwe | 2008-03-14 02:24:39 +0100 (Fri, 14 Mar 2008) | 8 lines
+
+Original v2 revision: 3142
+
+Fix broken flashrom build.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r205 | hailfinger | 2008-03-14 01:33:42 +0100 (Fri, 14 Mar 2008) | 7 lines
+
+Original v2 revision: 3141
+
+Fix up one forgotten revert in r3140.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r204 | hailfinger | 2008-03-14 01:02:25 +0100 (Fri, 14 Mar 2008) | 7 lines
+
+Original v2 revision: 3140
+
+Revert the delete of 82802ab.c in r3137.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r203 | uwe | 2008-03-13 19:52:51 +0100 (Thu, 13 Mar 2008) | 13 lines
+
+Original v2 revision: 3139
+
+Also print the chip vendor name in --list-supported output (trivial).
+
+Cosmetic changes in some files, partly bending the 80-characters-per-line
+rule in this special case, as the 80-character-limited version looks
+equally crappy even in an 80x25 console/xterm, so let's make it at least
+look good in a high-resolution xterm.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r202 | uwe | 2008-03-13 19:41:07 +0100 (Thu, 13 Mar 2008) | 8 lines
+
+Original v2 revision: 3138
+
+Also print the required -m option in --list-supported output (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r201 | hailfinger | 2008-03-13 13:43:31 +0100 (Thu, 13 Mar 2008) | 7 lines
+
+Original v2 revision: 3137
+
+Drop 82802ab.c as it is identical to sharplhf00l04.c.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r200 | uwe | 2008-03-12 13:28:40 +0100 (Wed, 12 Mar 2008) | 10 lines
+
+Original v2 revision: 3134
+
+Drop the useless rom.layout file. It's just an example, likely never
+been used in the last few years, and the contents are available in
+the README already anyway.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+
+------------------------------------------------------------------------
+r199 | uwe | 2008-03-12 12:54:51 +0100 (Wed, 12 Mar 2008) | 9 lines
+
+Original v2 revision: 3133
+
+Add --list-supported option to flashrom which lists the supported
+ROM chips, chipsets, and mainboards (Closes #90).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+
+------------------------------------------------------------------------
+r198 | uwe | 2008-03-04 17:29:54 +0100 (Tue, 04 Mar 2008) | 9 lines
+
+Original v2 revision: 3126
+
+Add missing license header to layout.c. The file was written by
+Stefan Reinauer for coresystems GmbH in 2005, as confirmed on IRC.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r197 | stepan | 2008-02-20 12:11:18 +0100 (Wed, 20 Feb 2008) | 12 lines
+
+Original v2 revision: 3110
+
+flashrom: Add board_enable for Artec Group DBE61 and DBE62
+
+Also add a comment about NULL subsystem IDs leaving the board entry out
+of auto-detection logic.
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r196 | uwe | 2008-02-15 00:22:20 +0100 (Fri, 15 Feb 2008) | 15 lines
+
+Original v2 revision: 3102
+
+With this small change it is possible to build flashrom again when
+specifying custom CFLAGS/LDFLAGS from the make command line like:
+
+  make CFLAGS="..." LDFLAGS="..."
+
+I need to do this when building flashrom in a cross compiler environment
+like buildroot for a foreign target.
+
+Signed-off-by: Clark Rawlins <clark@bit63.org>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r195 | uwe | 2008-02-11 15:32:45 +0100 (Mon, 11 Feb 2008) | 17 lines
+
+Original v2 revision: 3101
+
+flashrom: further cleanups to enable_flash_cs5536
+
+ - Remove the "enable write to flash" message, as the caller appears to
+   already report that.
+
+ - Move the 'modprobe msr' suggestions to the first lseek64 error handling, as
+   we get an error there already.
+
+ - Rename a perror string from "read" to "read msr", as we use the latter
+   already in this function for another read.
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r194 | hailfinger | 2008-02-09 03:03:06 +0100 (Sat, 09 Feb 2008) | 8 lines
+
+Original v2 revision: 3099
+
+Flashrom: Add board enable for VIA EPIA SP.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r193 | uwe | 2008-02-08 11:10:57 +0100 (Fri, 08 Feb 2008) | 9 lines
+
+Original v2 revision: 3098
+
+Improve error handling and make RCONF_DEFAULT_MSR address be a constant.
+Also, move a big code comment to the top of enable_flash_cs5536().
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r192 | uwe | 2008-02-08 10:59:58 +0100 (Fri, 08 Feb 2008) | 15 lines
+
+Original v2 revision: 3097
+
+This implements support for devices using AMD Geode companion chip
+CS5536 that have the Boot ROM on NOR flash that is directly connected to
+FLASH_CS3 (Boot Flash Chip Select).
+We need to write enable it in the NORF_CTL MSR register for flashrom to
+be able to write to it, including JEDEC probe commands.
+
+This patch allows us to stop using AMD gx_utils.ko for BIOS flashing on
+the DBE61.
+
+Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r191 | hailfinger | 2008-02-06 23:07:58 +0100 (Wed, 06 Feb 2008) | 12 lines
+
+Original v2 revision: 3091
+
+Handle JEDEC JEP106W continuation codes in SPI RDID. Some vendors like
+Programmable Micro Corp (PMC) need this.
+Both the serial and parallel flash JEDEC detection routines would
+benefit from a parity/sanity check of the vendor ID. Will do this later.
+
+Add support for the PMC Pm25LV family of SPI flash chips.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Chris Lingard  <chris@stockwith.co.uk>
+
+------------------------------------------------------------------------
+r190 | stuge | 2008-01-27 17:21:21 +0100 (Sun, 27 Jan 2008) | 9 lines
+
+Original v2 revision: 3082
+
+Make the vendor name optional in the -m flashrom parameter when there's only
+one board name that matches. The full syntax still works, and is required
+when two vendors have boards with the same names.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r189 | stuge | 2008-01-27 08:17:14 +0100 (Sun, 27 Jan 2008) | 7 lines
+
+Original v2 revision: 3080
+
+Forgot to add Spansion S25FL016A to README, trivial.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r188 | rminnich | 2008-01-26 08:35:47 +0100 (Sat, 26 Jan 2008) | 11 lines
+
+Original v2 revision: 3078
+
+Correctly disable the ROM area Write Protect bit in the Geode LX.
+
+Signed-off-by: Marc Jones <marc.jones@amd.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+Tested on the pcengines alix1c and works fine.
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+
+------------------------------------------------------------------------
+r187 | hailfinger | 2008-01-25 02:52:45 +0100 (Fri, 25 Jan 2008) | 8 lines
+
+Original v2 revision: 3074
+
+Add ids and chip entry for Spansion S25FL016A to flashrom, tested,
+working.
+
+Signed-off-by: Peter Stuge <peter@stuge.se>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r186 | hailfinger | 2008-01-22 17:03:19 +0100 (Tue, 22 Jan 2008) | 29 lines
+
+Original v2 revision: 3072
+
+Here is just a little and simple patch to get the MX25L3205D working.
+I've tested and verified the chip myself, and it seems to work
+everything like supposted, since Carl-Daniel has patched flashrom to
+use the read funktion on verifying. 
+
+"benchvice flashrom # ./flashrom -m gigabyte:m57sli -v test.4mb
+Calibrating delay loop... OK.
+No coreboot table found.
+Found chipset "NVIDIA MCP55", enabling flash write... OK.
+Found board "GIGABYTE GA-M57SLI-S4": enabling flash write... 
+Serial flash segment 0xfffe0000-0xffffffff enabled
+Serial flash segment 0x000e0000-0x000fffff enabled
+Serial flash segment 0xffee0000-0xffefffff disabled
+Serial flash segment 0xfff80000-0xfffeffff enabled
+LPC write to serial flash enabled
+serial flash pin 29
+OK.
+MX25L3205 found at physical address 0xffc00000.
+Flash part is MX25L3205 (4096 KB).
+Flash image seems to be a legacy BIOS. Disabling checks.
+Verifying flash... VERIFIED.
+benchvice flashrom # ls -l test.4mb
+-rw-r--r-- 1 root root 4194304 22. Jan 16:27 test.4mb
+
+Signed-off-by: Harald Gutmann <harald.gutmann@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r185 | hailfinger | 2008-01-22 16:19:01 +0100 (Tue, 22 Jan 2008) | 18 lines
+
+Original v2 revision: 3070
+
+Flashrom did not use the read function for verifying, it used direct memory
+access instead. That fails if the flash chip is not mapped completely.
+If the read function is set in struct flashchip, use it for verification
+as well.
+
+This fixes verification of all SPI flash chips >512 kByte behind an
+IT8716F flash translation chip.
+
+"MX25L8005 found at physical address 0xfff00000.
+Flash part is MX25L8005 (1024 KB).
+Flash image seems to be a legacy BIOS. Disabling checks.
+Verifying flash... VERIFIED."
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Harald Gutmann <harald.gutmann@gmx.net>
+
+------------------------------------------------------------------------
+r184 | hailfinger | 2008-01-22 15:37:31 +0100 (Tue, 22 Jan 2008) | 9 lines
+
+Original v2 revision: 3069
+
+Make sure we delay writing the next byte long enough in SPI byte
+programming.
+Minor formatting changes.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Harald Gutmann <harald.gutmann@gmx.net>
+
+------------------------------------------------------------------------
+r183 | hailfinger | 2008-01-22 00:55:08 +0100 (Tue, 22 Jan 2008) | 9 lines
+
+Original v2 revision: 3068
+
+Omitting the wait for SPI ready when there is no data to be read, e.g.
+readcnt==0 saves 10 seconds with the unconditional 10us delay, reducing
+programming time for SST25VF016B to 40-45 secs.
+
+Signed-off-by: Ronald Hoogenboom <hoogenboom30@zonnet.nl>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r182 | uwe | 2008-01-21 16:24:22 +0100 (Mon, 21 Jan 2008) | 11 lines
+
+Original v2 revision: 3067
+
+This patch adds version information to flashrom. Because 'v' and 'V'
+are already in use, the patch uses 'R' (for release) and, of course,
+'--version'.
+
+Signed-off-by: Bernhard Walle <bernhard.walle@gmx.de>
+Acked-by: Ulf Jordan <jordan@chalmers.se>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r181 | hailfinger | 2008-01-19 01:04:46 +0100 (Sat, 19 Jan 2008) | 9 lines
+
+Original v2 revision: 3061
+
+Support SPI flash chips bigger than 512 kByte sitting behind IT8716F
+Super I/O performing LPC-to-SPI flash translation.
+
+Signed-off-by: Ronald Hoogenboom <hoogenboom30@zonnet.nl>
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r180 | uwe | 2008-01-18 18:48:51 +0100 (Fri, 18 Jan 2008) | 8 lines
+
+Original v2 revision: 3059
+
+Minor documentation improvements/fixes in the README and manpage (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r179 | stepan | 2008-01-18 17:17:44 +0100 (Fri, 18 Jan 2008) | 7 lines
+
+Original v2 revision: 3058
+
+rename linuxbios_* files in utils repository.
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r178 | stepan | 2008-01-18 16:33:10 +0100 (Fri, 18 Jan 2008) | 8 lines
+
+Original v2 revision: 3054
+
+for some reasons the externals did not get committed.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r177 | duwe | 2008-01-11 01:32:07 +0100 (Fri, 11 Jan 2008) | 8 lines
+
+Original v2 revision: 3045
+
+This patch removes '\n' from the help output since this looks a bit strange.
+After the patch [...] The line length is still below 80 characters.
+
+Signed-off-by: Bernhard Walle <bernhard.walle@gmx.de>
+Acked-by: Torsten Duwe <duwe@lst.de>
+
+------------------------------------------------------------------------
+r176 | hailfinger | 2008-01-10 14:27:22 +0100 (Thu, 10 Jan 2008) | 7 lines
+
+Original v2 revision: 3042
+
+Enable MX25L8005 support in flashrom. The #defines were already there.
+
+Signed-off-by: Harald Gutmann <harald.gutmann@gmx.net>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r175 | hailfinger | 2008-01-07 14:48:51 +0100 (Mon, 07 Jan 2008) | 8 lines
+
+Original v2 revision: 3036
+
+Add support for the SST25VF040B 4 Mbit SPI flash chip.
+Straight from the data sheet, not tested.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r174 | rminnich | 2008-01-04 18:22:44 +0100 (Fri, 04 Jan 2008) | 6 lines
+
+Original v2 revision: 3033
+
+Add board enable for the gigabyte ga_2761gxdk board
+Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r173 | hailfinger | 2008-01-04 17:22:09 +0100 (Fri, 04 Jan 2008) | 8 lines
+
+Original v2 revision: 3032
+
+Print at least the vendor for SPI flash chips if the exact chip ID is
+unknown.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+------------------------------------------------------------------------
+r172 | hailfinger | 2007-12-31 15:05:08 +0100 (Mon, 31 Dec 2007) | 10 lines
+
+Original v2 revision: 3031
+
+Unfortunately, EN29F002T, EN29F002AT, EN29F002ANT, EN29F002NT all have
+exactly the same ID. Improve model number printing.
+
+Add EN29F002(A)(N)B support while I'm at it.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Markus Boas <bios@ryven.de>
+
+------------------------------------------------------------------------
+r171 | hailfinger | 2007-12-31 02:49:00 +0100 (Mon, 31 Dec 2007) | 22 lines
+
+Original v2 revision: 3030
+
+Add continuation ID support to jedec.c
+The continuation ID code does not go further than checking for IDs of
+the type 0x7fXX, but does this for vendor and product ID. The current
+published JEDEC spec has a list where the largest vendor ID is 7 bytes
+long, but all leading bytes are 0x7f. The list will grow in the future,
+and using a 64bit variable will not be enough anymore.
+Besides that, it seems that the location of the ID byte after the first
+continuation ID byte is very vendor specific, so we may have to revisit
+that code some time in the future.
+
+(Suggestion for a new encoding:
+Use a two-byte data type for the ID, the lower byte contains the only
+non-0x7f byte, the upper byte contains the number of 0x7f bytes used as
+prefix, which is the bank number minus 1 the vendor ID appears in.)
+
+Add support for EON EN29F002AT.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+
+------------------------------------------------------------------------
+r170 | hailfinger | 2007-12-31 02:18:26 +0100 (Mon, 31 Dec 2007) | 12 lines
+
+Original v2 revision: 3029
+
+This fixes a few vendor IDs to conform with JEDEC publication 106W
+(JEP106W), adds some device IDs and provides information about
+non-conforming IDs.
+The EON change is left to the patch adding EON chips.
+
+This patch should have no effect on code generation.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+
+------------------------------------------------------------------------
+r169 | hailfinger | 2007-12-29 12:05:59 +0100 (Sat, 29 Dec 2007) | 10 lines
+
+Original v2 revision: 3027
+
+All SPI chips mentioned in flashchips.c had their sector size listed as
+page size. Fix that. Page size is uniform 256 bytes for SPI.
+
+A sector/block size field in struct flashchip would be nice, though.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+
+------------------------------------------------------------------------
+r168 | hailfinger | 2007-12-29 11:15:58 +0100 (Sat, 29 Dec 2007) | 10 lines
+
+Original v2 revision: 3026
+
+Print the chip status register for all SPI chips on probe if verbose
+output is specified.
+Pretty-print the chip status register (including block lock information)
+for ST M25P family and Macronix MX25L family chips.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+
+------------------------------------------------------------------------
+r167 | hailfinger | 2007-12-29 11:14:38 +0100 (Sat, 29 Dec 2007) | 8 lines
+
+Original v2 revision: 3025
+
+Add 25VF016B support to flashrom. Untested, but verified against the
+data sheet.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+
+------------------------------------------------------------------------
+r166 | hailfinger | 2007-12-17 23:22:40 +0100 (Mon, 17 Dec 2007) | 9 lines
+
+Original v2 revision: 3012
+
+Add support for ST M25P05-A, M25P10-A, M25P20, M25P40, M25P16, M25P32,
+M25P64, M25P128 to flashrom. ST M25P80 support is already there.
+Not tested, but conforming to data sheets and double checked.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+------------------------------------------------------------------------
+r165 | hailfinger | 2007-12-17 15:33:32 +0100 (Mon, 17 Dec 2007) | 12 lines
+
+Original v2 revision: 3009
+
+To make it easier to add new SPI chips to flashchips.c, rename functions
+with multiple possible opcodes from linear numbering at the end (_1, _2)
+to include the opcode at the end (_60, _c7). That way, you only have to
+take a short look at the data sheet and choose the right function by
+appending the opcode listed in the data sheet.
+No functional changes.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+------------------------------------------------------------------------
+r164 | hailfinger | 2007-12-16 22:15:27 +0100 (Sun, 16 Dec 2007) | 8 lines
+
+Original v2 revision: 3008
+
+Add support for ST M25P80 chips to flashrom. Detection was tested.
+Print status register before erase to help debugging block locks.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Corey Osgood <corey.osgood@gmail.com>
+
+------------------------------------------------------------------------
+r163 | hailfinger | 2007-12-10 17:57:59 +0100 (Mon, 10 Dec 2007) | 14 lines
+
+Original v2 revision: 3003
+
+Add support for more atmel chips:
+AT49F002
+AT49F002N
+AT49F002T
+AT49F002NT
+
+Only tested the read function on AT49F002T.
+datasheet @ http://www.atmel.com/atmel/acrobat/doc1017.pdf
+
+Signed-off-by: Frederico Silva <frederico.silva@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r162 | uwe | 2007-12-04 22:49:06 +0100 (Tue, 04 Dec 2007) | 11 lines
+
+Original v2 revision: 2997
+
+Various coding style fixes, constification, fixed typos (trivial).
+
+Also, s/0xFF80/0xFFC0/ in the Acorp 6A815EPD board-enable, as per
+http://www.linuxbios.org/pipermail/linuxbios/2007-December/027750.html
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r161 | uwe | 2007-12-02 20:03:23 +0100 (Sun, 02 Dec 2007) | 9 lines
+
+Original v2 revision: 2995
+
+Add board-enable for Acorp 6A815EPD.
+
+Signed-off-by: Jonathan A. Kollasch <jakllsch@kollasch.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r160 | jcrouse | 2007-11-13 17:45:22 +0100 (Tue, 13 Nov 2007) | 11 lines
+
+Original v2 revision: 2967
+
+[LinuxBIOS] flashrom support for AMD Geode CS5536
+
+Attached is a patch that enables AMD Geode CS5536 chipset support.  I
+have tested it successfully on a MSM800 board from digital logic.
+
+Signed-off-by: Lane Brooks <lbrooks@mit.edu>
+Acked-by: Jordan Crouse <jordan.crouse@amd.com>
+
+
+------------------------------------------------------------------------
+r159 | hailfinger | 2007-11-13 15:56:54 +0100 (Tue, 13 Nov 2007) | 11 lines
+
+Original v2 revision: 2962
+
+Fix ATMEL 29C020 detection with flashrom. The JEDEC probe routine had
+a delay of 10 us after entering ID mode and this was insufficient for
+the 29C020. The data sheet claims we have to wait 10 ms, but tests have
+shown that 20 us suffice. Allow for variations in chip delays with a
+factor of 2 safety margin.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r158 | uwe | 2007-10-30 01:56:50 +0100 (Tue, 30 Oct 2007) | 11 lines
+
+Original v2 revision: 2903
+
+Add support for Intel 440MX systems.
+Add support for the Fujitsu MBM29F400TC flash part.
+
+Detection and reading works, writing is not tested.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r157 | stuge | 2007-10-25 06:11:11 +0200 (Thu, 25 Oct 2007) | 13 lines
+
+Original v2 revision: 2897
+
+Added Am29LV040B
+
+Looking through the sources of Uniflash utility I found that this chip
+is no more no less than low-voltage variant of Am29F040B but with
+different ID.
+
+So I created a very quick patch (attached).
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r156 | hailfinger | 2007-10-22 22:36:16 +0200 (Mon, 22 Oct 2007) | 7 lines
+
+Original v2 revision: 2884
+
+Flashrom: Add more Vendor IDs and ensure correct sorting in flash.h.
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+------------------------------------------------------------------------
+r155 | hailfinger | 2007-10-22 18:15:28 +0200 (Mon, 22 Oct 2007) | 8 lines
+
+Original v2 revision: 2881
+
+Introduce block and sector erase routines to flashrom, but do not use
+them yet.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r154 | hailfinger | 2007-10-18 19:56:42 +0200 (Thu, 18 Oct 2007) | 10 lines
+
+Original v2 revision: 2876
+
+Remove hardcoded wait from SPI write/erase routines and check the chip
+status register instead.
+This has been tested by Harald Gutmann <harald.gutmann@gmx.net> with a
+MX25L4005 chip.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r153 | uwe | 2007-10-18 02:29:05 +0200 (Thu, 18 Oct 2007) | 8 lines
+
+Original v2 revision: 2875
+
+Documentation fixes and updates (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r152 | hailfinger | 2007-10-18 02:24:07 +0200 (Thu, 18 Oct 2007) | 14 lines
+
+Original v2 revision: 2874
+
+Add generic SPI flash erase and write support to flashrom. The first
+chip the code was tested and verified with is the Macronix MX25L4005,
+but other chips should work as well.
+Timeouts are still hardcoded to data sheet maxima, but the status
+register checking code is already there.
+Thanks to Harald Gutmann for the initial code on which this is loosely
+based.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r151 | uwe | 2007-10-18 01:55:15 +0200 (Thu, 18 Oct 2007) | 8 lines
+
+Original v2 revision: 2873
+
+Some cosmetic cleanups in the flashrom code and output.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r150 | hailfinger | 2007-10-18 00:30:07 +0200 (Thu, 18 Oct 2007) | 10 lines
+
+Original v2 revision: 2868
+
+Fix wrong values/typos in chipset_enable.c. This has been confirmed by
+Ed Swierk in
+http://www.mail-archive.com/linuxbios@linuxbios.org/msg09788.html .
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r149 | uwe | 2007-10-17 01:36:34 +0200 (Wed, 17 Oct 2007) | 15 lines
+
+Original v2 revision: 2866
+
+Multiple flashrom fixes:
+
+ - Install binary in /usr/sbin (not /usr/bin), as it's a root-only tool.
+
+ - Rename manpage from flashrom.1 to flashrom.8, as section 8 contains
+   "System administration commands (usually only for root)".
+
+ - Actually install the manpage upon 'make install'.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r148 | hailfinger | 2007-10-16 23:18:43 +0200 (Tue, 16 Oct 2007) | 8 lines
+
+Original v2 revision: 2864
+
+Add Gigabyte M61P-S3 SPI flash support to board_enable.c
+
+Signed-off-by: Michael van der Kolff <mvanderkolff@gmail.com>
+Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+
+------------------------------------------------------------------------
+r147 | hailfinger | 2007-10-16 23:09:06 +0200 (Tue, 16 Oct 2007) | 9 lines
+
+Original v2 revision: 2863
+
+Convert the existing it8716f_* functions to generic_spi_* functions by
+applying abstraction and wrapping.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r146 | stepan | 2007-10-15 23:45:29 +0200 (Mon, 15 Oct 2007) | 17 lines
+
+Original v2 revision: 2858
+
+(forgot to add spi.c)
+
+Move SPI code out of board_enable.c where it started its life. The SPI
+chip finding and SPI chip accessor code is moved as well. This can be
+split later if we feel like it.
+
+The non-use of svn cp is intentional because the only history we'd have
+to preserve are a few commits which were early prototypes of chip
+identification code. For those who intend to look at that history, they
+can look at board_enable.c revision 2853.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r145 | stepan | 2007-10-15 23:44:47 +0200 (Mon, 15 Oct 2007) | 15 lines
+
+Original v2 revision: 2857
+
+Move SPI code out of board_enable.c where it started its life. The SPI
+chip finding and SPI chip accessor code is moved as well. This can be
+split later if we feel like it.
+
+The non-use of svn cp is intentional because the only history we'd have
+to preserve are a few commits which were early prototypes of chip
+identification code. For those who intend to look at that history, they
+can look at board_enable.c revision 2853.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r144 | rminnich | 2007-10-12 23:22:40 +0200 (Fri, 12 Oct 2007) | 10 lines
+
+Original v2 revision: 2850
+
+Changes to flashrom to support the K8N-NEO3, first tested at Google on GSOC day :-)
+
+Also minor changes to remove tab-space combinations where possible. 
+
+Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
+Signed-off-by: David Hendricks <david.hendricks@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r143 | uwe | 2007-10-10 19:42:20 +0200 (Wed, 10 Oct 2007) | 8 lines
+
+Original v2 revision: 2847
+
+Revert my last cleanup patch.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r142 | uwe | 2007-10-10 18:31:30 +0200 (Wed, 10 Oct 2007) | 8 lines
+
+Original v2 revision: 2846
+
+Cosmetic changes to make the flashrom output more consistent (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r141 | stepan | 2007-10-04 08:26:41 +0200 (Thu, 04 Oct 2007) | 11 lines
+
+Original v2 revision: 2820
+
+[FLASHROM] Fix the help, and print a message when nothing happens
+
+The help implied that writes happen by default, which they don't.  Fix
+the text, and say something when we dont specify any commands.
+
+Signed-off-by: Jordan Crouse <jordan.crouse@amd.com>    
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r140 | ward | 2007-10-02 17:49:25 +0200 (Tue, 02 Oct 2007) | 19 lines
+
+Original v2 revision: 2817
+
+
+This patch aims to restructure SPI flash support in a more reasonable
+way. It introduces a generic SPI host driver for the IT8716F Super I/O
+which will enable easy SPI programming without having to care for the
+peculiarities of the SPI host.
+
+To activate probing for the IT8716F, you have to use the gigabyte:m57sli
+mainboard override. SPI support will then use the gathered SPI host data
+to access the SPI flash.
+
+This has been tested sucessfully by Ward Vandewege <ward@gnu.org> on the
+GA-M57SLI v2.0, which has a MX25L4005 SPI flash part.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+
+------------------------------------------------------------------------
+r139 | ward | 2007-09-27 16:29:57 +0200 (Thu, 27 Sep 2007) | 12 lines
+
+Original v2 revision: 2811
+
+
+Add preliminary SPI flash identification support for SPI chips attached
+to ITE IT8716F Super I/O. Right now this is hardcoded to the Gigabyte
+M57SLI board. It works only with rev 2.0 of the board, but it will bail
+out on earlier versions, so no damage can occur.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Ward Vandewege <ward@gnu.org>
+
+
+------------------------------------------------------------------------
+r138 | uwe | 2007-09-11 17:58:18 +0200 (Tue, 11 Sep 2007) | 9 lines
+
+Original v2 revision: 2770
+
+Change out/in combinations to pci_read/write_byte in
+sis630 chipset enable.
+
+Signed-off-by: Alex Beregszaszi <alex@rtfs.hu>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r137 | uwe | 2007-09-09 22:24:29 +0200 (Sun, 09 Sep 2007) | 8 lines
+
+Original v2 revision: 2769
+
+Remove useless 'extern' keywords (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r136 | uwe | 2007-09-09 22:21:05 +0200 (Sun, 09 Sep 2007) | 8 lines
+
+Original v2 revision: 2768
+
+Add '(C)' where it's missing (for consistency reasons).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r135 | uwe | 2007-09-09 22:02:45 +0200 (Sun, 09 Sep 2007) | 16 lines
+
+Original v2 revision: 2767
+
+Add missing license header to udelay.c.
+
+I'm self-ack'ing this, as the origin of the code in udelay.c (and thus
+the license and copyright owner) is pretty clear.
+
+The code which is now in udelay.c was split out from flash_rom.c in r1428,
+and flash_rom.c, in turn, has been around since the beginning and had a
+'Copyright 2000 Silicon Integrated System Corporation' line as well as the
+usual GPLv2-or-later license header.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r134 | uwe | 2007-09-08 16:36:01 +0200 (Sat, 08 Sep 2007) | 9 lines
+
+Original v2 revision: 2764
+
+Add a copy of the GPL in the flashrom repository as it's an independent
+project (being packaged by distros, among other things).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r133 | uwe | 2007-08-30 12:17:50 +0200 (Thu, 30 Aug 2007) | 8 lines
+
+Original v2 revision: 2753
+
+Add support for the Winbond W29EE011.
+
+Signed-off-by: Markus Boas <ryven@ryven.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r132 | uwe | 2007-08-30 12:11:08 +0200 (Thu, 30 Aug 2007) | 8 lines
+
+Original v2 revision: 2752
+
+Add support for the Winbond W29C040P.
+
+Signed-off-by: Markus Boas <ryven@ryven.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r131 | uwe | 2007-08-29 19:52:32 +0200 (Wed, 29 Aug 2007) | 9 lines
+
+Original v2 revision: 2751
+
+Change all flashrom license headers to use our standard format.
+No changes in content of the files.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r130 | uwe | 2007-08-23 18:08:21 +0200 (Thu, 23 Aug 2007) | 8 lines
+
+Original v2 revision: 2748
+
+Cosmetic fixes (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r129 | uwe | 2007-08-23 17:20:38 +0200 (Thu, 23 Aug 2007) | 8 lines
+
+Original v2 revision: 2747
+
+Drop duplicated code (copies of plain JEDEC functions).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r128 | uwe | 2007-08-23 15:34:59 +0200 (Thu, 23 Aug 2007) | 8 lines
+
+Original v2 revision: 2746
+
+Drop a bunch of useless header files, merge them into flash.h.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r127 | uwe | 2007-08-23 12:20:40 +0200 (Thu, 23 Aug 2007) | 8 lines
+
+Original v2 revision: 2745
+
+Move code into *.c files, there's no reason to have it in header files.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r126 | stuge | 2007-08-13 06:10:32 +0200 (Mon, 13 Aug 2007) | 12 lines
+
+Original v2 revision: 2744
+
+Fix bug in probe_28sf040() causing flash corruption on SST49LF160C verify.
+
+The first byte of the flash chip was read at the start of the function
+and later written back to address 0 if the flash chip was not identified
+as SST28SF040, which means most of the time. This write caused corruption
+of flash contents when verifying a SST49LF160C part.
+
+Signed-off-by: Ed Swierk <eswierk@arastra.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r125 | uwe | 2007-08-11 18:59:11 +0200 (Sat, 11 Aug 2007) | 9 lines
+
+Original v2 revision: 2743
+
+flashrom: Add board enable for the EPoX EP-BX3.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Peter Stuge <peter@stuge.se>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r124 | uwe | 2007-07-27 05:32:45 +0200 (Fri, 27 Jul 2007) | 8 lines
+
+Original v2 revision: 2742
+
+flashrom: Add missing supported flash chips to the README (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r123 | uwe | 2007-07-25 19:55:45 +0200 (Wed, 25 Jul 2007) | 13 lines
+
+Original v2 revision: 2741
+
+This patch adds support for the M50FLW040A, M50FLW040B, M50FLW080A,
+M50FLW080B, M50FW080, M50FW016, M50LPW116, M29W010B flash chips made
+by ST to flashrom.
+
+The patch is based on the data sheets of the chips and has not been
+tested at all.
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r122 | uwe | 2007-07-24 20:18:05 +0200 (Tue, 24 Jul 2007) | 11 lines
+
+Original v2 revision: 2740
+
+This patch adds support for ST M50FW040 and ST M29W040B to flashrom.
+Only reading from the chips was tested; writing support is untested.
+
+Thanks to G?\195?\188rkan Seng?\195?\188n <gurkan@linuks.mine.nu> for testing!
+
+Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r121 | uwe | 2007-07-04 19:51:49 +0200 (Wed, 04 Jul 2007) | 10 lines
+
+Original v2 revision: 2732
+
+Flashrom: Add support for Tyan Tomcat K7M.
+
+Same board enable as Asus A7V8-MX. Tested by Reinhard Max.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r120 | uwe | 2007-06-06 23:35:45 +0200 (Wed, 06 Jun 2007) | 14 lines
+
+Original v2 revision: 2715
+
+Fix up and document the AMD CS5530/CS5530A support in flashrom.
+
+The previous code was pretty unreadable, undocumented and did some totally
+unrelated things (such as mucking with the game port or port 0x92).
+
+This version is tested with a 256 KB chip and should work for the
+CS5530 and CS5530A.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r119 | uwe | 2007-06-05 17:02:18 +0200 (Tue, 05 Jun 2007) | 9 lines
+
+Original v2 revision: 2713
+
+flashrom: Document the newly supported IBM x3455 board and the
+now-supported Broadcom HT-1000 chipset (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r118 | stepan | 2007-06-05 14:51:52 +0200 (Tue, 05 Jun 2007) | 8 lines
+
+Original v2 revision: 2712
+
+Move GPIO settings to board specific code for IBM x3455
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r117 | stepan | 2007-06-05 12:28:39 +0200 (Tue, 05 Jun 2007) | 8 lines
+
+Original v2 revision: 2711
+
+Add support for BCM HT1000 chipset to flashrom. Tested on IBM x3455.
+(trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r116 | uwe | 2007-05-24 21:17:29 +0200 (Thu, 24 May 2007) | 8 lines
+
+Original v2 revision: 2696
+
+Minor cosmetics (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r115 | stepan | 2007-05-24 11:26:39 +0200 (Thu, 24 May 2007) | 8 lines
+
+Original v2 revision: 2693
+
+drop leftover includes (trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r114 | stepan | 2007-05-24 11:08:36 +0200 (Thu, 24 May 2007) | 7 lines
+
+Original v2 revision: 2692
+
+some copyright analysis
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r113 | stepan | 2007-05-24 10:48:10 +0200 (Thu, 24 May 2007) | 7 lines
+
+Original v2 revision: 2691
+
+factor out register mapping code (trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r112 | stepan | 2007-05-23 20:24:58 +0200 (Wed, 23 May 2007) | 8 lines
+
+Original v2 revision: 2690
+
+Unify mmap error messages in flashrom (trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r111 | stepan | 2007-05-23 19:20:56 +0200 (Wed, 23 May 2007) | 12 lines
+
+Original v2 revision: 2689
+
+big cosmetic offensive on flashrom. (trivial)
+* Give decent names to virt_addr and virt_addr_2
+* add some comments
+* move virtual addresses to the end of the struct,
+  so they dont mess up the initializer.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r110 | uwe | 2007-05-21 23:39:08 +0200 (Mon, 21 May 2007) | 8 lines
+
+Original v2 revision: 2686
+
+Add support for the Winbond W39V040FA chip.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r109 | uwe | 2007-05-20 18:16:13 +0200 (Sun, 20 May 2007) | 15 lines
+
+Original v2 revision: 2677
+
+Flashrom: add support for ASUS P5A (Socket 7, ALi based).
+
+* Add support for the ALi M1533 to chipset_enable.c
+* Add some SMBus poking needed for the ASUS P5A, to board_enable.c
+
+Since PCI subsystem IDs are worthless with this board, people will
+have to name the board directly.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r108 | uwe | 2007-05-09 12:17:44 +0200 (Wed, 09 May 2007) | 13 lines
+
+Original v2 revision: 2643
+
+Fix coding style of flashrom by running indent on all files:
+
+  indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs *.[ch]
+
+Some minor fixups were required, and maybe a few more cosmetic
+change?\209?\149 are needed.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r107 | stuge | 2007-05-04 06:47:04 +0200 (Fri, 04 May 2007) | 17 lines
+
+Original v2 revision: 2627
+
+Add WinBond Super IO helpers.
+
+* These helpers severely clear up winbond superio usage.
+* Removed board_iwill_dk8_htx as it can be replaced by
+  board_agami_aruma (Mondrian Nuessle).
+* Renamed board_agami_aruma to w83627hf_gpio24_raise.
+* Clarified comments in w83627hf_gpio24_raise, and added
+  some things from the old iwill code.
+* Moved all board functions name argument to const.
+  (warning breaks build)
+* Moved iwill entry in board_pciid_enables.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r106 | uwe | 2007-05-03 12:09:23 +0200 (Thu, 03 May 2007) | 10 lines
+
+Original v2 revision: 2624
+
+Enable flashing on the IWILL DK8-HTX board by configuring the Super I/O
+to set the right GPIO pins, so write protection is disabled.
+
+Signed-off-by: Mondrian Nuessle <nuessle@uni-mannheim.de>
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r105 | stuge | 2007-04-28 04:22:59 +0200 (Sat, 28 Apr 2007) | 13 lines
+
+Original v2 revision: 2621
+
+Add initial support for the following flash chips:
+
+ - Atmel AT29C020
+ - STMicroelectronics M29F002B
+ - STMicroelectronics M29F002T
+ - STMicroelectronics M29F002NT
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Signed-off-by: Roger Zauner <roger@eskimo.com>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+------------------------------------------------------------------------
+r104 | stepan | 2007-04-14 18:32:59 +0200 (Sat, 14 Apr 2007) | 9 lines
+
+Original v2 revision: 2610
+
+Exit on return code of read_layout and print error message to stderr
+instead of stdout (trivial)
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r103 | stepan | 2007-04-12 01:31:45 +0200 (Thu, 12 Apr 2007) | 9 lines
+
+Original v2 revision: 2603
+
+Rename flash_rom.c to flashrom.c. The tool is called 'flashrom' after
+all.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r102 | uwe | 2007-04-10 00:59:22 +0200 (Tue, 10 Apr 2007) | 8 lines
+
+Original v2 revision: 2601
+
+flashrom: Add VIA CX700 to the list of supported southbridges (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r101 | stepan | 2007-04-10 00:27:45 +0200 (Tue, 10 Apr 2007) | 8 lines
+
+Original v2 revision: 2599
+
+add support for CX700 builtin southbridge
+Signed-off-by: Randall Philipson <rtphilipson@cox.net>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r100 | stepan | 2007-04-06 13:58:03 +0200 (Fri, 06 Apr 2007) | 13 lines
+
+Original v2 revision: 2585
+
+Trivial (cosmetic) cleanup:
+* Only open /dev/mem once and do it early.
+* Drop extern for function prototypes.
+* Minimize ts5300 impact in probe_flash()
+
+This cleanup will making ICH7 SPI support quite some easier.
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r99 | stepan | 2007-04-05 00:45:58 +0200 (Thu, 05 Apr 2007) | 21 lines
+
+Original v2 revision: 2581
+
+flashrom: split flash_enable.c into chipset_enable.c and board_enable.c
+
+This splits up the ROM Write enable code into chipset specific and
+board specific parts. This of course means that a lot of code is
+plainly moved about.
+
+* Allows for linuxbios name matching and pci-subsystem id matching.
+  The latter uses a double set to properly distuinguish boards despite
+  of some known vendors being lax about it.
+* Fixes GPIO15 being raised on every VT8235 southbridge, regardless of what
+  that line actually controls; rom on EPIA-M, backlight on mitac 8999 laptop.
+* Adds flashrom support for Asus A7V400-MX (KM400 + VT8235)
+* Island aruma was renamed agami aruma, the board specific code now got
+  adjusted. A set of pci-ids was retrieved from source code.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r98 | uwe | 2007-04-01 22:00:32 +0200 (Sun, 01 Apr 2007) | 8 lines
+
+Original v2 revision: 2578
+
+Drop useless and partly even incorrect comments (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r97 | uwe | 2007-04-01 21:44:21 +0200 (Sun, 01 Apr 2007) | 8 lines
+
+Original v2 revision: 2577
+
+Coding style fixes (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r96 | uwe | 2007-03-31 21:48:38 +0200 (Sat, 31 Mar 2007) | 8 lines
+
+Original v2 revision: 2575
+
+Flashrom: Add support for the ICH7-DH southbridge (untested).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+------------------------------------------------------------------------
+r95 | stepan | 2007-03-22 15:51:45 +0100 (Thu, 22 Mar 2007) | 9 lines
+
+Original v2 revision: 2573
+
+This is a trivial cosmetic fix. Without it, the error message might look like:
+Image size doesnt match: Success
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r94 | uwe | 2007-03-07 00:49:49 +0100 (Wed, 07 Mar 2007) | 11 lines
+
+Original v2 revision: 2570
+
+The attached patch adds additional PCI IDs for MCP55 LPC devices to
+flashrom. 0x0360 is needed to support the DFI LANParty NF590SLI, and I
+am deducing the others based on pci_ids.h in the Linux kernel.
+
+Signed-off-by: Ed Swierk <eswierk@arastra.com>
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r93 | uwe | 2007-03-02 23:16:38 +0100 (Fri, 02 Mar 2007) | 15 lines
+
+Original v2 revision: 2568
+
+flashrom: Fix wrong VT8235 flash enable failed warning.
+
+* Fix harmless but worrying warning where the return value of
+  pci_write_byte is misinterpreted.
+* Hash together VT8231 and VT8235 code into VT823x. VT8231 is the better
+  implementation, but lacked the write protect disable code that's
+  apparently needed for VT8235.
+
+Signed-off-by: Luc Verhaegen <libv@skynet.be>
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r92 | uwe | 2007-03-02 03:25:36 +0100 (Fri, 02 Mar 2007) | 9 lines
+
+Original v2 revision: 2565
+
+Add Winbond W39V080A support to Flashrom.
+
+Signed-off-by: David Hendricks <david.hendricks@gmail.com>
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r91 | stepan | 2007-02-28 22:50:15 +0100 (Wed, 28 Feb 2007) | 8 lines
+
+Original v2 revision: 2564
+
+Add support for the Gigabyte m57sli-s4 board to flashrom.
+
+Signed-off-by: Ward Vandewege <ward@gnu.org>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r90 | uwe | 2007-02-16 15:36:12 +0100 (Fri, 16 Feb 2007) | 11 lines
+
+Original v2 revision: 2553
+
+Currently the flashrom Makefile tries to detect whether pciutils-devel
+is installed, but the test also fails if zlib-devel is missing. This
+patch changes the error message accordingly.
+
+Signed-off-by: Ed Swierk <eswierk@arastra.com>
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r89 | stepan | 2007-02-06 20:53:51 +0100 (Tue, 06 Feb 2007) | 9 lines
+
+Original v2 revision: 2551
+
+Include src/include/boot/linuxbios_tables.h in the flashrom source
+tree to make it compilable independant of the LinuxBIOS source code.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r88 | stepan | 2007-02-06 20:47:50 +0100 (Tue, 06 Feb 2007) | 23 lines
+
+Original v2 revision: 2550
+
+This patch is a rework of Adam Kaufman's Solaris patch.
+
+* flash.h:
+  - add a license header
+  - add system definitions
+* flash_enable.c:
+  - put io priviledge access in one single place
+  - add includes required for Solaris.
+* lbtable.c, flash_rom.c, 82802ab.c:
+  - use MEM_DEV so it works on Solaris
+* sst49lfxxxc.c, sharplhf00l04.c, sst_fwhub.c, 82802ab.c
+  - drop unneeded include to sys/io.h
+* Makefile
+  - adapt to Solaris specifics.
+
+Signed-off-by: Adam Kaufman <adam.kaufman@pinnacle.com>
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Adam Kaufman <adam.kaufman@pinnacle.com>
+
+
+------------------------------------------------------------------------
+r87 | uwe | 2007-01-27 14:39:06 +0100 (Sat, 27 Jan 2007) | 8 lines
+
+Original v2 revision: 2539
+
+Add support for the SST 49LF160C.
+
+Signed-off-by: Alan Carvalho de Assis <acassis@gmail.com>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r86 | uwe | 2007-01-24 12:09:03 +0100 (Wed, 24 Jan 2007) | 9 lines
+
+Original v2 revision: 2538
+
+Delete superfluous and incorrect comment (trivial).
+See also http://www.openbios.org/pipermail/linuxbios/2007-January/018042.html.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r85 | uwe | 2007-01-22 21:21:17 +0100 (Mon, 22 Jan 2007) | 11 lines
+
+Original v2 revision: 2537
+
+Add support for the SST-49LF004C, SST-49LF008C, SST-49LF016C in flashrom.
+Also add suport for NVIDIA MCP55.
+
+Signed-off-by: Yinghai Lu <yinghai.lu@amd.com>
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Peter Stuge <peter@stuge.se>
+
+
+
+------------------------------------------------------------------------
+r84 | uwe | 2006-12-20 15:59:56 +0100 (Wed, 20 Dec 2006) | 8 lines
+
+Original v2 revision: 2531
+
+Improve flashrom description in the manpage a bit (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r83 | uwe | 2006-12-20 15:53:22 +0100 (Wed, 20 Dec 2006) | 8 lines
+
+Original v2 revision: 2530
+
+Update flashrom requirements in the README (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r82 | uwe | 2006-12-14 01:59:41 +0100 (Thu, 14 Dec 2006) | 10 lines
+
+Original v2 revision: 2524
+
+Add an install target to the flashrom Makefile which installs flashrom
+into /usr/local/bin. Closes #54.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+
+------------------------------------------------------------------------
+r81 | uwe | 2006-12-04 09:20:40 +0100 (Mon, 04 Dec 2006) | 8 lines
+
+Original v2 revision: 2518
+
+Update list of supported flash chips in the flashrom README (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r80 | uwe | 2006-12-04 09:15:47 +0100 (Mon, 04 Dec 2006) | 11 lines
+
+Original v2 revision: 2517
+
+List the supported flash chips and southbridges in the flashrom
+README file (trivial).
+
+Closes #52.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r79 | uwe | 2006-11-22 16:27:29 +0100 (Wed, 22 Nov 2006) | 8 lines
+
+Original v2 revision: 2507
+
+Fix location of the bug tracker in the manpage (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r78 | stepan | 2006-11-22 01:29:51 +0100 (Wed, 22 Nov 2006) | 21 lines
+
+Original v2 revision: 2505
+
+apply patch from Giampiero Giancipoli <gianci@email.it>:
+
+Fixed write_page_write_jedec() in jedec.c. Added a check-reprogram loop
+in the same function, to come around the high page write failure rate on
+some boards.
+
+This patch includes the changes suggested by Ron to simplify the control
+flow.
+
+It also includes trivial changes by me to make flashrom build on newer 
+systems (libpci needs libz now). I also made a small type case compile fix
+and proper return code handling in one or two places.
+
+Signed-off-by: Giampiero Giancipoli <gianci@email.it>
+Signed-off-by: Ronald G Minnich <rminnich@gmail.com>
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r77 | stepan | 2006-11-22 00:51:08 +0100 (Wed, 22 Nov 2006) | 6 lines
+
+Original v2 revision: 2504
+
+Add support for ASD AE49F2008 
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de> (trivial patch)
+
+------------------------------------------------------------------------
+r76 | stepan | 2006-11-22 00:48:51 +0100 (Wed, 22 Nov 2006) | 8 lines
+
+Original v2 revision: 2503
+
+flashrom: Only write the flash if the image has the same size
+
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Segher Boessenkool <segher@kernel.crashing.org>
+
+
+------------------------------------------------------------------------
+r75 | uwe | 2006-11-21 16:09:05 +0100 (Tue, 21 Nov 2006) | 8 lines
+
+Original v2 revision: 2502
+
+Rename SM_ID to SYNCMOS_ID (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r74 | uwe | 2006-11-21 16:02:27 +0100 (Tue, 21 Nov 2006) | 9 lines
+
+Original v2 revision: 2501
+
+Add support for the SyncMOS S29C51001T, S29C51004T, and S29C31004T
+flash chips to flashrom (closes: #50).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Ronald G. Minnich <rminnich@gmail.com>
+
+
+------------------------------------------------------------------------
+r73 | uwe | 2006-11-20 21:32:35 +0100 (Mon, 20 Nov 2006) | 8 lines
+
+Original v2 revision: 2500
+
+Cosmetic fixes and typos (trivial).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r72 | uwe | 2006-11-20 21:03:07 +0100 (Mon, 20 Nov 2006) | 8 lines
+
+Original v2 revision: 2499
+
+Support for the 256K SyncMos S29C51002T flash.
+
+Signed-off-by: Giampiero Giancipoli <gianci@email.it>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
+
+
+------------------------------------------------------------------------
+r71 | stepan | 2006-11-07 14:48:46 +0100 (Tue, 07 Nov 2006) | 7 lines
+
+Original v2 revision: 2494
+
+Instead of checking the first byte only, the whole part is checked now. This
+will detect any improper erase, closes #31
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Uwe Hermann <uwe@hermann-uwe.de> 
+
+------------------------------------------------------------------------
+r70 | uwe | 2006-11-07 12:16:21 +0100 (Tue, 07 Nov 2006) | 10 lines
+
+Original v2 revision: 2493
+
+Fix some code comments of the Intel PIIX4/PIIX4E/PIIX4M code.
+Add detailed instructions on how and where to get the datasheet,
+its name, and order number (Closes #34).
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de> 
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r69 | stepan | 2006-11-07 11:22:20 +0100 (Tue, 07 Nov 2006) | 7 lines
+
+Original v2 revision: 2492
+
+Support for VIA VT82C686 in flashrom utility (trivial)
+closes #30
+Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r68 | uwe | 2006-11-05 19:26:08 +0100 (Sun, 05 Nov 2006) | 9 lines
+
+Original v2 revision: 2489
+
+Add support for Intel PIIX4/PIIX4E/PIIX4M-based mainboards to flashrom.
+Tested on real hardware, reading, detecting and writing various chips works.
+
+Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
+Acked-by: Stefan Reinauer <stepan@coresystems.de>
+
+
+------------------------------------------------------------------------
+r67 | stepan | 2006-10-14 23:04:49 +0200 (Sat, 14 Oct 2006) | 5 lines
+
+Original v2 revision: 2456
+
+* add vt8237 support (Uwe Hermann)
+* add more MCP51 support (me)
+
+------------------------------------------------------------------------
+r66 | stepan | 2006-10-08 00:59:03 +0200 (Sun, 08 Oct 2006) | 6 lines
+
+Original v2 revision: 2450
+
+here's a small patch to add support for the SST 49LF020A to flashrom.
+by Uwe Hermann <uwe@hermann-uwe.de>
+X-Signed-Off-By: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r65 | stepan | 2006-10-07 02:23:51 +0200 (Sat, 07 Oct 2006) | 6 lines
+
+Original v2 revision: 2449
+
+Tiny patch to show the size of the detected flash part 
+from Uwe Hermann <uwe@hermann-uwe.de>
+X-Signed-Off-By: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r64 | stepan | 2006-10-07 02:21:13 +0200 (Sat, 07 Oct 2006) | 6 lines
+
+Original v2 revision: 2448
+
+Fix flashrom for sst49lf080a and small print bug,
+by Roman Kononov <kononov195-lbl@yahoo.com>.
+X-Signed-Off-By: Stefan Reinauer <stepan@coresystems.de>
+
+------------------------------------------------------------------------
+r63 | stepan | 2006-09-21 15:09:22 +0200 (Thu, 21 Sep 2006) | 4 lines
+
+Original v2 revision: 2431
+
+abuild manpage and other fixes from Uwe Hermann. Thank you!
+
+------------------------------------------------------------------------
+r62 | stepan | 2006-09-06 17:48:48 +0200 (Wed, 06 Sep 2006) | 4 lines
+
+Original v2 revision: 2395
+
+Add patch from Uwe Hermann to support more ICH southbridges
+
+------------------------------------------------------------------------
+r61 | stepan | 2006-08-25 21:21:42 +0200 (Fri, 25 Aug 2006) | 4 lines
+
+Original v2 revision: 2390
+
+Print a warning if southbridge is not known to flashrom.
+
+------------------------------------------------------------------------
+r60 | stepan | 2006-08-23 16:33:54 +0200 (Wed, 23 Aug 2006) | 4 lines
+
+Original v2 revision: 2386
+
+Removing $Id$ tags as they have no meaning in SVN
+
+------------------------------------------------------------------------
+r59 | stepan | 2006-08-03 12:49:09 +0200 (Thu, 03 Aug 2006) | 4 lines
+
+Original v2 revision: 2358
+
+some documentation updates by Uwe and some smaller ones by me.
+
+------------------------------------------------------------------------
+r58 | stepan | 2006-08-01 01:37:17 +0200 (Tue, 01 Aug 2006) | 5 lines
+
+Original v2 revision: 2354
+
+Add support for SST39SF040 and SST39SF010A
+apply C.-D. Hailfinger's patch for Winbond part (untested)
+
+------------------------------------------------------------------------
+r57 | stepan | 2006-07-28 01:29:02 +0200 (Fri, 28 Jul 2006) | 4 lines
+
+Original v2 revision: 2349
+
+add flashrom manpage from Uwe Hermann
+
+------------------------------------------------------------------------
+r56 | stepan | 2006-07-19 17:13:21 +0200 (Wed, 19 Jul 2006) | 8 lines
+
+Original v2 revision: 2341
+
+From: Scott Tsai, scott.tsai <AT> arima.com.tw
+Tested on my home Shuttle SB51G box.
+data sheet:
+http://www.alldatasheet.com/datasheet-pdf/pdf/47674/WINBOND/W49V002FAP.html
+
+
+------------------------------------------------------------------------
+r55 | stepan | 2006-06-30 22:07:50 +0200 (Fri, 30 Jun 2006) | 4 lines
+
+Original v2 revision: 2336
+
+add support for EFST F49B002UA (untested)
+
+------------------------------------------------------------------------
+r54 | stepan | 2006-06-25 11:56:45 +0200 (Sun, 25 Jun 2006) | 4 lines
+
+Original v2 revision: 2332
+
+add support for PMC 49FL002 as used in the RD1-PMC2
+
+------------------------------------------------------------------------
+r53 | stepan | 2006-06-14 17:58:41 +0200 (Wed, 14 Jun 2006) | 4 lines
+
+Original v2 revision: 2321
+
+new flash part
+
+------------------------------------------------------------------------
+r52 | stepan | 2006-03-31 13:36:06 +0200 (Fri, 31 Mar 2006) | 8 lines
+
+Original v2 revision: 2230
+
+* https://openbios.org/roundup/linuxbios/issue96 - SST_49LF040B flash support for flashrom
+* https://openbios.org/roundup/linuxbios/issue99 - add ICH4-M support to flashrom
+
+both from scott.tsai <AT> arima.com.tw
+
+
+------------------------------------------------------------------------
+r51 | stepan | 2006-03-31 13:26:55 +0200 (Fri, 31 Mar 2006) | 6 lines
+
+Original v2 revision: 2229
+
+* support for Winbond W39V040A
+* Support for ATI SB400 (RS480 chipset)
+* Support for Intel ICH7 (from Scott Tsai, scott.tsai <AT> arima.com.tw)
+
+------------------------------------------------------------------------
+r50 | stepan | 2006-03-20 22:37:54 +0100 (Mon, 20 Mar 2006) | 4 lines
+
+Original v2 revision: 2220
+
+compilation fix for gcc 4.0.2 (SUSE10)
+
+------------------------------------------------------------------------
+r49 | stepan | 2006-03-19 23:30:42 +0100 (Sun, 19 Mar 2006) | 5 lines
+
+Original v2 revision: 2215
+
+redo ts5300 auto.c
+add ts5300 flag as comment in flashrom utility Makefile
+
+------------------------------------------------------------------------
+r48 | stepan | 2006-03-17 23:35:56 +0100 (Fri, 17 Mar 2006) | 5 lines
+
+Original v2 revision: 2210
+
+update dumpmmcr.c utility
+another flash chip that doesn't clog the serial line
+
+------------------------------------------------------------------------
+r47 | stepan | 2006-03-16 17:57:41 +0100 (Thu, 16 Mar 2006) | 7 lines
+
+Original v2 revision: 2205
+
+- speed up flash verification by only printing 1 of 4096 addresses
+- support for flashing technologic system ts5300 SBC (needs -DTS5300 in
+  the makefile)
+
+
+------------------------------------------------------------------------
+r46 | stepan | 2006-03-16 17:46:19 +0100 (Thu, 16 Mar 2006) | 5 lines
+
+Original v2 revision: 2204
+
+make am29f040b driver more solid by printing every 4096th flash address.
+This fixes the timing when flashing over a serial console.
+
+------------------------------------------------------------------------
+r45 | stepan | 2006-03-16 17:44:07 +0100 (Thu, 16 Mar 2006) | 4 lines
+
+Original v2 revision: 2203
+
+support for Am29F016D
+
+------------------------------------------------------------------------
+r44 | rminnich | 2006-03-14 20:58:14 +0100 (Tue, 14 Mar 2006) | 7 lines
+
+Original v2 revision: 2197
+
+Fix for nehemiah
+other fixes for gx2 ram init. 
+
+support for sharplfg00l04 -- not working yet.
+
+------------------------------------------------------------------------
+r43 | rminnich | 2006-03-01 17:11:05 +0100 (Wed, 01 Mar 2006) | 4 lines
+
+Original v2 revision: 2189
+
+a few new items and mods for ollie
+
+------------------------------------------------------------------------
+r42 | rminnich | 2006-02-24 18:10:10 +0100 (Fri, 24 Feb 2006) | 4 lines
+
+Original v2 revision: 2183
+
+added support for ICH5
+
+------------------------------------------------------------------------
+r41 | stepan | 2006-02-24 14:47:26 +0100 (Fri, 24 Feb 2006) | 4 lines
+
+Original v2 revision: 2182
+
+new flashchip support by Leon Woestenberg <leonw@mailcan.com>
+
+------------------------------------------------------------------------
+r40 | rminnich | 2006-02-23 18:16:44 +0100 (Thu, 23 Feb 2006) | 4 lines
+
+Original v2 revision: 2180
+
+added sharp flash
+
+------------------------------------------------------------------------
+r39 | stepan | 2006-01-04 17:42:57 +0100 (Wed, 04 Jan 2006) | 4 lines
+
+Original v2 revision: 2151
+
+pass on return values
+
+------------------------------------------------------------------------
+r38 | stepan | 2005-12-18 19:40:46 +0100 (Sun, 18 Dec 2005) | 5 lines
+
+Original v2 revision: 2147
+
+redo image checking in conversion case. Please update to this
+release if you are using flashrom.
+
+------------------------------------------------------------------------
+r37 | stepan | 2005-12-18 17:41:10 +0100 (Sun, 18 Dec 2005) | 6 lines
+
+Original v2 revision: 2146
+
+* make -v switch print debug messages.
+* do case insensitive comparison of mainboards, as wished on the
+  mailinglist
+
+------------------------------------------------------------------------
+r36 | stepan | 2005-12-01 17:19:24 +0100 (Thu, 01 Dec 2005) | 4 lines
+
+Original v2 revision: 2117
+
+issue 40, make flashrom utility build process more solid.
+
+------------------------------------------------------------------------
+r35 | stepan | 2005-12-01 11:51:08 +0100 (Thu, 01 Dec 2005) | 4 lines
+
+Original v2 revision: 2114
+
+mention build dependencies in Makefile.
+
+------------------------------------------------------------------------
+r34 | ollie | 2005-11-26 22:55:36 +0100 (Sat, 26 Nov 2005) | 3 lines
+
+Original v2 revision: 2111
+
+flasrom update from Stefan, resovle issue 21
+------------------------------------------------------------------------
+r33 | ollie | 2005-08-03 17:04:53 +0200 (Wed, 03 Aug 2005) | 3 lines
+
+Original v2 revision: 1988
+
+bug fix from Jonathan McDowell <noodles@earth.li>
+------------------------------------------------------------------------
+r32 | arch | 2005-07-06 19:13:46 +0200 (Wed, 06 Jul 2005) | 7 lines
+
+Original v2 revision: 1946
+
+Revision: linuxbios@linuxbios.org--devel/freebios--devel--2.0--patch-30
+Creator:  Yinghai Lu <yhlu@tyan.com>
+
+Nvidia Ck804 support
+
+------------------------------------------------------------------------
+r31 | ollie | 2005-01-11 03:48:22 +0100 (Tue, 11 Jan 2005) | 4 lines
+
+Original v2 revision: 1852
+
+*** empty log message ***
+
+------------------------------------------------------------------------
+r30 | ollie | 2004-12-08 21:10:01 +0100 (Wed, 08 Dec 2004) | 4 lines
+
+Original v2 revision: 1815
+
+added -E option for chip erase, remove duplicated code
+
+------------------------------------------------------------------------
+r29 | ollie | 2004-12-08 03:10:33 +0100 (Wed, 08 Dec 2004) | 4 lines
+
+Original v2 revision: 1814
+
+add retry to write_byte_program_jedec(), 99% success rate
+
+------------------------------------------------------------------------
+r28 | ollie | 2004-12-07 18:19:04 +0100 (Tue, 07 Dec 2004) | 4 lines
+
+Original v2 revision: 1813
+
+enable LPC decoding for 1 MB more addresss, for supporting SST49LF00xA/B
+
+------------------------------------------------------------------------
+r27 | ollie | 2004-12-07 04:15:51 +0100 (Tue, 07 Dec 2004) | 5 lines
+
+Original v2 revision: 1812
+
+SST49LF00[2,3,4] should use
+the same driver as 49LF008
+
+------------------------------------------------------------------------
+r26 | yhlu | 2004-10-20 07:07:16 +0200 (Wed, 20 Oct 2004) | 4 lines
+
+Original v2 revision: 1693
+
+Tyan update to work with new CPU Config
+
+------------------------------------------------------------------------
+r25 | rminnich | 2004-09-30 18:37:01 +0200 (Thu, 30 Sep 2004) | 4 lines
+
+Original v2 revision: 1651
+
+support for sst firmware hub
+
+------------------------------------------------------------------------
+r24 | rminnich | 2004-09-28 22:32:17 +0200 (Tue, 28 Sep 2004) | 4 lines
+
+Original v2 revision: 1650
+
+use hex print in id1, id2
+
+------------------------------------------------------------------------
+r23 | rminnich | 2004-09-28 22:09:06 +0200 (Tue, 28 Sep 2004) | 4 lines
+
+Original v2 revision: 1649
+
+add support for ICH4. more i955pm stuff.
+
+------------------------------------------------------------------------
+r22 | ollie | 2004-09-07 23:31:47 +0200 (Tue, 07 Sep 2004) | 4 lines
+
+Original v2 revision: 1647
+
+code reformat
+
+------------------------------------------------------------------------
+r21 | rminnich | 2004-04-13 21:10:48 +0200 (Tue, 13 Apr 2004) | 4 lines
+
+Original v2 revision: 1496
+
+add missing return at 205
+
+------------------------------------------------------------------------
+r20 | ollie | 2004-03-27 01:31:03 +0100 (Sat, 27 Mar 2004) | 4 lines
+
+Original v2 revision: 1487
+
+data tye consistence
+
+------------------------------------------------------------------------
+r19 | ollie | 2004-03-27 01:18:15 +0100 (Sat, 27 Mar 2004) | 4 lines
+
+Original v2 revision: 1486
+
+removed false alarm of erase/write, use verify '-v' if you are not sure about the integrity
+
+------------------------------------------------------------------------
+r18 | ollie | 2004-03-22 23:19:17 +0100 (Mon, 22 Mar 2004) | 4 lines
+
+Original v2 revision: 1464
+
+more jedec standard consolidatation.
+
+------------------------------------------------------------------------
+r17 | ollie | 2004-03-20 18:39:43 +0100 (Sat, 20 Mar 2004) | 4 lines
+
+Original v2 revision: 1459
+
+rmove unused #define and function declaretion
+
+------------------------------------------------------------------------
+r16 | ollie | 2004-03-20 18:05:01 +0100 (Sat, 20 Mar 2004) | 5 lines
+
+Original v2 revision: 1458
+
+I have no idea what i was trying to show off when I used the while loop rather
+than for loop. Please forgive me, I was too young 4 years ago.
+
+------------------------------------------------------------------------
+r15 | ollie | 2004-03-20 17:46:10 +0100 (Sat, 20 Mar 2004) | 4 lines
+
+Original v2 revision: 1457
+
+consolidate more jedec standard code
+
+------------------------------------------------------------------------
+r14 | ollie | 2004-03-19 23:10:07 +0100 (Fri, 19 Mar 2004) | 4 lines
+
+Original v2 revision: 1456
+
+remove duplicated code
+
+------------------------------------------------------------------------
+r13 | dhendricks | 2004-03-18 22:59:05 +0100 (Thu, 18 Mar 2004) | 4 lines
+
+Original v2 revision: 1439
+
+Added support for SST49LF0xxA parts.
+
+------------------------------------------------------------------------
+r12 | dhendricks | 2004-03-18 22:55:22 +0100 (Thu, 18 Mar 2004) | 4 lines
+
+Original v2 revision: 1438
+
+Added support for more SST 49lf0xxA parts
+
+------------------------------------------------------------------------
+r11 | ollie | 2004-03-18 21:35:33 +0100 (Thu, 18 Mar 2004) | 4 lines
+
+Original v2 revision: 1437
+
+forgot a semicolon
+
+------------------------------------------------------------------------
+r10 | ollie | 2004-03-18 21:31:54 +0100 (Thu, 18 Mar 2004) | 4 lines
+
+Original v2 revision: 1436
+
+removed unused code in pm49fl004, remove experimental delay in sst49lf040
+
+------------------------------------------------------------------------
+r9 | ollie | 2004-03-18 21:27:33 +0100 (Thu, 18 Mar 2004) | 4 lines
+
+Original v2 revision: 1435
+
+fixed stupid i++ evalution order bug
+
+------------------------------------------------------------------------
+r8 | ollie | 2004-03-18 20:40:07 +0100 (Thu, 18 Mar 2004) | 4 lines
+
+Original v2 revision: 1434
+
+fixed 32bit v.s. 64bit long int arithematics
+
+------------------------------------------------------------------------
+r7 | ollie | 2004-03-18 00:03:37 +0100 (Thu, 18 Mar 2004) | 6 lines
+
+Original v2 revision: 1433
+
+removed spd_dump.c, it has nothing to do with flashing flash parts.
+use standard product ID exit method for w49f002u
+move udelay stuff into its own file
+
+------------------------------------------------------------------------
+r6 | ollie | 2004-03-17 23:22:08 +0100 (Wed, 17 Mar 2004) | 4 lines
+
+Original v2 revision: 1428
+
+move utility functions into new source files
+
+------------------------------------------------------------------------
+r5 | dhendricks | 2004-03-17 22:47:30 +0100 (Wed, 17 Mar 2004) | 4 lines
+
+Original v2 revision: 1422
+
+Added support for SST49LF040
+
+------------------------------------------------------------------------
+r4 | rminnich | 2004-02-14 00:09:54 +0100 (Sat, 14 Feb 2004) | 4 lines
+
+Original v2 revision: 1376
+
+fix makefile
+
+------------------------------------------------------------------------
+r3 | rminnich | 2004-02-10 22:34:18 +0100 (Tue, 10 Feb 2004) | 4 lines
+
+Original v2 revision: 1375
+
+now we support 8111 and these parts.
+
+------------------------------------------------------------------------
+r2 | rminnich | 2003-11-05 17:36:57 +0100 (Wed, 05 Nov 2003) | 4 lines
+
+Original v2 revision: 1255
+
+fix volatile
+
+------------------------------------------------------------------------
+r1 | rminnich | 2003-10-25 19:01:29 +0200 (Sat, 25 Oct 2003) | 4 lines
+
+Original v2 revision: 1232
+
+due to popular demand, added flash_and_burn to the freebios2 tree.
+
+------------------------------------------------------------------------
diff --git a/Documentation/mysteries_intel.txt b/Documentation/mysteries_intel.txt
new file mode 100644 (file)
index 0000000..10cb37d
--- /dev/null
@@ -0,0 +1,110 @@
+= BBAR on ICH8 =
+ There is no sign of BBAR (BIOS Base Address Configuration Register) in the
+ public datasheet (or specification update) of the ICH8. Also, the offset of
+ that register has changed between ICH7 (SPIBAR + 50h) and ICH9 (SPIBAR +
+ A0h), so we have no clue if or where it is on ICH8. Out current policy is to
+ not touch it at all and assume/hope it is 0.
+
+= Accesses beyond region bounds in descriptor mode =
+ Intel's flash image tool will always expand the last region so that it covers
+ the whole flash chip, but some boards ship with a different configuration.
+ It seems that in descriptor mode all addresses outside the used regions can not
+ be accessed whatsoever. This is not specified anywhere publicly as far as we
+ could tell. flashrom does not handle this explicitly yet. It will just fail
+ when trying to touch an address outside of any region.
+ See also http://www.flashrom.org/pipermail/flashrom/2011-August/007606.html
+
+= (Un)locking the ME region =
+ If the ME region is locked by the FRAP register in descriptor mode, the host
+ software is not allowed to read or write any address inside that region.
+ Although the chipset datasheets specify that "[t]he contents of this register
+ are that of the Flash Descriptor" [PANTHER], this is not entirely true.
+ The firmware has to fill at least some of the registers involved. It is not
+ known when they become read-only or any other details, but there is at least
+ one HM67-based board, that provides an user-changeable setting in the firmware
+ user interface to enable ME region updates that lead to a FRAP content that is
+ not equal to the descriptor region bits [NC9B].
+
+ There are different ways to unlock access:
+
+ - A pin strap: Flash Descriptor Security Override Strap (as indicated by the
+   Flash Descriptor Override Pin Strap Status (FDOPSS) in HSFS. That pin is
+   probably not accessible to end users on consumer boards (every Intel doc i
+   have seen stresses that this is for debugging in manufacturing only and
+   should not be available for end users).
+   The ME indicates this in bits [19:16] (Operation Mode) in the HFS register of
+   the HECI/MEI PCI device by setting them to 4 (SECOVR_JMPR) [MODE_CTRL].
+
+ - Intel Management Engine BIOS Extension (MEBx) Disable
+   This option may be available to end users on some boards usually accessible
+   by hitting ctrl+p after BIOS POST. Quote: "'Disabling' the Intel ME does not
+   really disable it: it causes the Intel ME code to be halted at an early stage
+   of the Intel ME's booting so that the system has no traffic originating from
+   the Intel ME on any of the buses." [MEBX] The ME indicates this in
+   bits [19:16] (Operation Mode) in the HFS register of the HECI/MEI PCI device
+   by setting them to 3 (Soft Temporary Disable) [MODE_CTRL].
+
+ - Previous to Ibex Peak/5 Series chipsets removing the DIMM from slot (or
+   channel?) #0 disables the ME completely, which may give the host access to
+   the ME region.
+
+ - HMRFPO (Host ME Region Flash Protection Override) Enable MEI command
+   This is the most interesting one because it allows to temporarily disable
+   the ME region protection by software. The ME indicates this in bits [19:16]
+   (Operation Mode) in the HFS register of the HECI/MEI PCI device by setting
+   them to 5 (SECOVER_MEI_MSG) [MODE_CTRL].
+
+== MEI/HECI ==
+ Communication between the host software and the different services provided by
+ the ME is done via a packet-based protocol that uses MMIO transfers to one or
+ more virtual PCI devices. Upon this layer there exist various services that can
+ be used to read out hardware management values (e.g. temperatures, fan speeds
+ etc.). The lower levels of that protocol are well documented:
+ The locations/offsets of the PCI MMIO registers are noted in the chipset
+ datasheets. The actually communication is documented in a whitepaper [DCMI] and
+ an outdated as well as a current Linux kernel implementation (currently in
+ staging/ exist [KERNEL]. There exists a patch that re-implements this in user
+ space (as part of flashrom).
+== Problems ==
+ The problem is that only very few higher level protocols are documented publicly,
+ especially the bunch of messages that contain the HMRFPO commands is probably
+ well protected and only documented in ME-specific docs and the BIOS writer's
+ guides. We are aware of a few leaked documents though that give us a few hints
+ about it, but nothing substantial regarding its implementation.
+ The documents are somewhat contradicting each other in various points which
+ might be due to factual changes in process of time or due to the different
+ capabilities of the ME firmwares, example:
+ Intel's Flash Programming Tool (FPT) "automatically stops ME writing to SPI
+ ME Region, to prevent both writing at the same time, causing data corruption." [ME8]
+ "FPT is not HMRFPO-capable, so needs [the help of the FDOPS pin] HDA_SDO if
+ used to update the ME Region." [SPS]
+ When looking at the various ME firmware editions (and different chipsets), things
+ get very unclear. Some docs say that HMRFPO needs to be sent before End-of-POST
+ (EOP), others say that the ME region can be updated in the field or that some
+ vendor tools use it for updates. This needs to be investigated further before
+ drawing any conclusion.
+
+[PANTHER]   Intel 7 Series Chipset Family Platform Controller Hub (PCH) Datasheet
+            Document Number: 326776, April 2012, page 857
+[NC9B]      Jetway NC9B flashrom v0.9.5.2-r1517 log with ME region unlocked.
+            NB: "FRAP 0e0f" vs. "FLMSTR1 0a0b".
+            http://paste.flashrom.org/view.php?id=1215
+[MODE_CTRL] Client Platform Enabling Tour: Platform Software
+            Document Number: 439167, Revision 1.2, page 52
+[MEBX]      Intel Management Engine BIOS Extension (MEBX) User's Guide
+            Revision 1.2, Section 3.1 and 3.5
+[DCMI]      DCMI Host Interface Specification
+            Revision 1.0
+[KERNEL]    http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=drivers/staging/mei;hb=HEAD
+[SPI_PROG]  Ibex Peak SPI Programming Guide
+            Document Number: 403598, Revision 1.3, page 79
+[ME8]       Manufacturing with Intel Management Engine (ME) Firmware 8.X on Intel 7 Series
+            Revision 2.0, page 59
+[SPS]       Manufacturing with Intel Management Engine (ME) on Intel C600 Series Chipset 1
+            for Romley Server 2 Platforms using Server Platform Services (SPS) Firmware
+            Revision 2.2, page 51
diff --git a/Documentation/serprog-protocol.txt b/Documentation/serprog-protocol.txt
new file mode 100644 (file)
index 0000000..a3a4863
--- /dev/null
@@ -0,0 +1,109 @@
+Serial Flasher Protocol Specification - version 1 (0x01 return value == 1)
+
+Command And Answer Sequence - all commands give an answer.
+PC: COMMAND(8bit) <parameters determined by opcode>
+DEV: ACK/NAK(8bit) <OPTIONAL RETURN BYTES (only if ACK)> / nothing
+Command 0x10 (SYNCNOP) has a special return of NAK+ACK for synchronization.
+
+ACK = 0x06
+NAK = 0x15
+
+All multibyte values are little-endian. Addresses and lengths are 24-bit.
+
+COMMAND        Description                     Parameters                      Return Value
+0x00   NOP                             none                            ACK
+0x01   Query programmer iface version  none                            ACK + 16bit version (nonzero)
+0x02   Query supported commands bitmap none                            ACK + 32 bytes (256 bits) of supported cmds flags
+0x03   Query programmer name           none                            ACK + 16 bytes string (null padding) / NAK
+0x04   Query serial buffer size        none                            ACK + 16bit size / NAK
+0x05   Query supported bustypes        none                            ACK + 8-bit flags (as per flashrom) / NAK
+0x06   Query connected address lines   none                            ACK + 8bit line count / NAK
+0x07   Query operation buffer size     none                            ACK + 16bit size / NAK
+0x08   Query maximum write-n length    none                            ACK + 24bit length (0==2^24) / NAK
+0x09   Read byte                       24-bit addr                     ACK + BYTE / NAK
+0x0A   Read n bytes                    24-bit addr + 24-bit length     ACK + length bytes / NAK
+0x0B   Initialize operation buffer     none                            ACK / NAK
+0x0C   Write to opbuf: Write byte      24-bit addr + 8-bit byte        ACK / NAK (NOTE: takes 5 bytes in opbuf)
+0x0D   Write to opbuf: Write n         24-bit length + 24-bit addr +   ACK / NAK (NOTE: takes 7+n bytes in opbuf)
+                                        + length bytes of data
+0x0E   Write to opbuf: delay           32-bit usecs                    ACK / NAK (NOTE: takes 5 bytes in opbuf)
+0x0F   Execute operation buffer        none                            ACK / NAK
+0x10   Sync NOP                        none                            NAK + ACK (for synchronization)
+0x11   Query maximum read-n length     none                            ACK + 24-bit length (0==2^24) / NAK
+0x12   Set used bustype                8-bit flags (as with 0x05)      ACK / NAK
+0x13   Perform SPI operation           24-bit slen + 24-bit rlen       ACK + rlen bytes of data / NAK
+                                        + slen bytes of data
+0x??   unimplemented command - invalid.
+
+
+Additional information of the above commands:
+       About unimplemented commands / startup sequence:
+               Only commands allowed to be used without checking anything are 0x00,0x10 and 0x01 (NOP,SYNCNOP,Q_IFACE).
+               If 0x01 doesn't return 1, dont do anything if you dont support a newer protocol.
+               Then, check support for any other opcode (except 0x02) by using 0x02 (Q_CMDMAP).
+       0x02 (Q_CMDMAP):
+               The map's bits are mapped as follows:
+               cmd 0 support: byte 0 bit 0
+               cmd 1 support: byte 0 bit 1
+               cmd 7 support: byte 0 bit 7
+               cmd 8 support: byte 1 bit 0, and so on.
+       0x04 (Q_SERBUF):
+               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.
+       0x06 (Q_CHIPSIZE):
+               Only applicable to parallel programmers.
+               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
+               reported maximum write-n without problems.
+       0x0F (O_EXEC):
+               Execute operation buffer will also clear it, regardless of the return value.
+       0x11 (Q_RDNMAXLEN):
+               If this command is not supported, assume return of 0 (2^24).
+       0x12 (S_BUSTYPE):
+               Set's the used bustype if the programmer can support more than one flash protocol.
+               Sending a byte with more than 1 bit set will make the programmer decide among them
+               on it's own. Bit values as with Q_BUSTYPE.
+       0x13 (O_SPIOP):
+               Send and receive bytes via SPI.
+               Maximum slen is Q_WRNMAXLEN in case Q_BUSTYPE returns SPI only or S_BUSTYPE was used
+               to set SPI exclusively before. Same for rlen and Q_RDNMAXLEN.
+               This operation is immediate, meaning it doesnt use the operation buffer.
+       About mandatory commands:
+               The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10,
+               but one can't really do anything with these commands.
+               Support for the following commands is necessary for flashrom to operate properly:
+               S_CMD_Q_SERBUF, S_CMD_Q_OPBUF, S_CMD_Q_WRNMAXLEN, S_CMD_R_BYTE,
+               S_CMD_R_NBYTES, S_CMD_O_INIT, S_CMD_O_WRITEB, S_CMD_O_WRITEN,
+               S_CMD_O_DELAY, S_CMD_O_EXEC.
+               In addition, support for these commands is recommended:
+               S_CMD_Q_PGMNAME, S_CMD_Q_BUSTYPE, S_CMD_Q_CHIPSIZE (if parallel).
+
+
+This define listing should help C coders - (it's here to be the single source for copying - will be a .h someday i think)
+#define S_ACK 0x06
+#define S_NAK 0x15
+#define S_CMD_NOP              0x00            /* No operation                                 */
+#define S_CMD_Q_IFACE           0x01            /* Query interface version                      */
+#define S_CMD_Q_CMDMAP         0x02            /* Query supported commands bitmap              */
+#define S_CMD_Q_PGMNAME         0x03            /* Query programmer name                        */
+#define S_CMD_Q_SERBUF          0x04            /* Query Serial Buffer Size                     */
+#define S_CMD_Q_BUSTYPE         0x05            /* Query supported bustypes                     */
+#define S_CMD_Q_CHIPSIZE        0x06            /* Query supported chipsize (2^n format)        */
+#define S_CMD_Q_OPBUF           0x07            /* Query operation buffer size                  */
+#define S_CMD_Q_WRNMAXLEN      0x08            /* Query Write to opbuf: Write-N maximum length */
+#define S_CMD_R_BYTE            0x09            /* Read a single byte                           */
+#define S_CMD_R_NBYTES          0x0A            /* Read n bytes                                 */
+#define S_CMD_O_INIT            0x0B            /* Initialize operation buffer                  */
+#define S_CMD_O_WRITEB          0x0C            /* Write opbuf: Write byte with address         */
+#define S_CMD_O_WRITEN         0x0D            /* Write to opbuf: Write-N                      */
+#define S_CMD_O_DELAY           0x0E            /* Write opbuf: udelay                          */
+#define S_CMD_O_EXEC            0x0F            /* Execute operation buffer                     */
+#define S_CMD_SYNCNOP          0x10            /* Special no-operation that returns NAK+ACK    */
+#define S_CMD_Q_RDNMAXLEN      0x11            /* Query read-n maximum length                  */
+#define S_CMD_S_BUSTYPE                0x12            /* Set used bustype(s).                         */
+#define S_CMD_O_SPIOP          0x13            /* Perform SPI operation.                       */
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..a733885
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,755 @@
+#
+# This file is part of the flashrom project.
+#
+# Copyright (C) 2005 coresystems GmbH <stepan@coresystems.de>
+# 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; 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
+#
+
+PROGRAM = flashrom
+
+CC      ?= gcc
+STRIP   ?= strip
+INSTALL = install
+DIFF    = diff
+PREFIX  ?= /usr/local
+MANDIR  ?= $(PREFIX)/share/man
+CFLAGS  ?= -Os -Wall -Wshadow
+EXPORTDIR ?= .
+AR      ?= ar
+RANLIB  ?= ranlib
+
+WARNERROR ?= yes
+
+ifeq ($(WARNERROR), yes)
+CFLAGS += -Werror
+endif
+
+# HOST_OS is only used to work around local toolchain issues.
+HOST_OS        ?= $(shell uname)
+ifeq ($(HOST_OS), MINGW32_NT-5.1)
+# Explicitly set CC = gcc on MinGW, otherwise: "cc: command not found".
+CC = gcc
+endif
+ifneq ($(HOST_OS), SunOS)
+STRIP_ARGS = -s
+endif
+
+# Determine the destination processor architecture.
+# IMPORTANT: The following line must be placed before TARGET_OS is ever used
+# (of course), but should come after any lines setting CC because the line
+# below uses CC itself.
+override TARGET_OS := $(strip $(shell LC_ALL=C $(CC) $(CPPFLAGS) -E os.h 2>/dev/null | grep -v '^\#' | grep '"' | cut -f 2 -d'"'))
+
+ifeq ($(TARGET_OS), Darwin)
+CPPFLAGS += -I/opt/local/include -I/usr/local/include
+# DirectHW framework can be found in the DirectHW library.
+LDFLAGS += -framework IOKit -framework DirectHW -L/opt/local/lib -L/usr/local/lib
+endif
+ifeq ($(TARGET_OS), FreeBSD)
+CPPFLAGS += -I/usr/local/include
+LDFLAGS += -L/usr/local/lib
+endif
+ifeq ($(TARGET_OS), OpenBSD)
+CPPFLAGS += -I/usr/local/include
+LDFLAGS += -L/usr/local/lib
+endif
+ifeq ($(TARGET_OS), DOS)
+EXEC_SUFFIX := .exe
+CPPFLAGS += -I../libgetopt -I../libpci/include
+# DJGPP has odd uint*_t definitions which cause lots of format string warnings.
+CPPFLAGS += -Wno-format
+# FIXME Check if we can achieve the same effect with -L../libgetopt -lgetopt
+LIBS += ../libgetopt/libgetopt.a
+# Bus Pirate, Serprog and Pony-SPI are not supported under DOS (missing serial support).
+ifeq ($(CONFIG_BUSPIRATE_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_BUSPIRATE_SPI=yes
+else
+override CONFIG_BUSPIRATE_SPI = no
+endif
+ifeq ($(CONFIG_SERPROG), yes)
+UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes
+else
+override CONFIG_SERPROG = no
+endif
+ifeq ($(CONFIG_PONY_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_PONY_SPI=yes
+else
+override CONFIG_PONY_SPI = no
+endif
+# Dediprog and FT2232 are not supported under DOS (missing USB support).
+ifeq ($(CONFIG_DEDIPROG), yes)
+UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
+else
+override CONFIG_DEDIPROG = no
+endif
+ifeq ($(CONFIG_FT2232_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
+else
+override CONFIG_FT2232_SPI = no
+endif
+endif
+
+# FIXME: Should we check for Cygwin/MSVC as well?
+ifeq ($(TARGET_OS), MinGW)
+EXEC_SUFFIX := .exe
+# MinGW doesn't have the ffs() function, but we can use gcc's __builtin_ffs().
+CFLAGS += -Dffs=__builtin_ffs
+# libusb-win32/libftdi stuff is usually installed in /usr/local.
+CPPFLAGS += -I/usr/local/include
+LDFLAGS += -L/usr/local/lib
+# Serprog is not supported under Windows/MinGW (missing sockets support).
+ifeq ($(CONFIG_SERPROG), yes)
+UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes
+else
+override CONFIG_SERPROG = no
+endif
+# For now we disable all PCI-based programmers on Windows/MinGW (no libpci).
+ifeq ($(CONFIG_INTERNAL), yes)
+UNSUPPORTED_FEATURES += CONFIG_INTERNAL=yes
+else
+override CONFIG_INTERNAL = no
+endif
+ifeq ($(CONFIG_RAYER_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_RAYER_SPI=yes
+else
+override CONFIG_RAYER_SPI = no
+endif
+ifeq ($(CONFIG_NIC3COM), yes)
+UNSUPPORTED_FEATURES += CONFIG_NIC3COM=yes
+else
+override CONFIG_NIC3COM = no
+endif
+ifeq ($(CONFIG_GFXNVIDIA), yes)
+UNSUPPORTED_FEATURES += CONFIG_GFXNVIDIA=yes
+else
+override CONFIG_GFXNVIDIA = no
+endif
+ifeq ($(CONFIG_SATASII), yes)
+UNSUPPORTED_FEATURES += CONFIG_SATASII=yes
+else
+override CONFIG_SATASII = no
+endif
+ifeq ($(CONFIG_ATAHPT), yes)
+UNSUPPORTED_FEATURES += CONFIG_ATAHPT=yes
+else
+override CONFIG_ATAHPT = no
+endif
+ifeq ($(CONFIG_DRKAISER), yes)
+UNSUPPORTED_FEATURES += CONFIG_DRKAISER=yes
+else
+override CONFIG_DRKAISER = no
+endif
+ifeq ($(CONFIG_NICREALTEK), yes)
+UNSUPPORTED_FEATURES += CONFIG_NICREALTEK=yes
+else
+override CONFIG_NICREALTEK = no
+endif
+ifeq ($(CONFIG_NICNATSEMI), yes)
+UNSUPPORTED_FEATURES += CONFIG_NICNATSEMI=yes
+else
+override CONFIG_NICNATSEMI = no
+endif
+ifeq ($(CONFIG_NICINTEL), yes)
+UNSUPPORTED_FEATURES += CONFIG_NICINTEL=yes
+else
+override CONFIG_NICINTEL = no
+endif
+ifeq ($(CONFIG_NICINTEL_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_NICINTEL_SPI=yes
+else
+override CONFIG_NICINTEL_SPI = no
+endif
+ifeq ($(CONFIG_OGP_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_OGP_SPI=yes
+else
+override CONFIG_OGP_SPI = no
+endif
+ifeq ($(CONFIG_SATAMV), yes)
+UNSUPPORTED_FEATURES += CONFIG_SATAMV=yes
+else
+override CONFIG_SATAMV = no
+endif
+endif
+
+ifeq ($(TARGET_OS), libpayload)
+CPPFLAGS += -DSTANDALONE
+ifeq ($(CONFIG_DUMMY), yes)
+UNSUPPORTED_FEATURES += CONFIG_DUMMY=yes
+else
+override CONFIG_DUMMY = no
+endif
+ifeq ($(CONFIG_BUSPIRATE_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_BUSPIRATE_SPI=yes
+else
+override CONFIG_BUSPIRATE_SPI = no
+endif
+ifeq ($(CONFIG_SERPROG), yes)
+UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes
+else
+override CONFIG_SERPROG = no
+endif
+# Dediprog and FT2232 are not supported with libpayload (missing libusb support)
+ifeq ($(CONFIG_DEDIPROG), yes)
+UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
+else
+override CONFIG_DEDIPROG = no
+endif
+ifeq ($(CONFIG_FT2232_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
+else
+override CONFIG_FT2232_SPI = no
+endif
+endif
+
+ifneq ($(TARGET_OS), Linux)
+ifeq ($(CONFIG_LINUX_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_LINUX_SPI=yes
+else
+override CONFIG_LINUX_SPI = no
+endif
+endif
+
+# Determine the destination processor architecture.
+# IMPORTANT: The following line must be placed before ARCH is ever used
+# (of course), but should come after any lines setting CC because the line
+# below uses CC itself.
+override ARCH := $(strip $(shell LC_ALL=C $(CC) $(CPPFLAGS) -E arch.h 2>/dev/null | grep -v '^\#' | grep '"' | cut -f 2 -d'"'))
+
+# PCI port I/O support is unimplemented on PPC/MIPS and unavailable on ARM.
+# Right now this means the drivers below only work on x86.
+ifneq ($(ARCH), x86)
+ifeq ($(CONFIG_NIC3COM), yes)
+UNSUPPORTED_FEATURES += CONFIG_NIC3COM=yes
+else
+override CONFIG_NIC3COM = no
+endif
+ifeq ($(CONFIG_NICREALTEK), yes)
+UNSUPPORTED_FEATURES += CONFIG_NICREALTEK=yes
+else
+override CONFIG_NICREALTEK = no
+endif
+ifeq ($(CONFIG_NICNATSEMI), yes)
+UNSUPPORTED_FEATURES += CONFIG_NICNATSEMI=yes
+else
+override CONFIG_NICNATSEMI = no
+endif
+ifeq ($(CONFIG_RAYER_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_RAYER_SPI=yes
+else
+override CONFIG_RAYER_SPI = no
+endif
+ifeq ($(CONFIG_ATAHPT), yes)
+UNSUPPORTED_FEATURES += CONFIG_ATAHPT=yes
+else
+override CONFIG_ATAHPT = no
+endif
+ifeq ($(CONFIG_SATAMV), yes)
+UNSUPPORTED_FEATURES += CONFIG_SATAMV=yes
+else
+override CONFIG_SATAMV = no
+endif
+endif
+
+CHIP_OBJS = jedec.o stm50flw0x0x.o w39.o w29ee011.o \
+       sst28sf040.o m29f400bt.o 82802ab.o pm49fl00x.o \
+       sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o \
+       a25.o at25.o opaque.o sfdp.o en29lv640b.o
+
+LIB_OBJS = layout.o
+
+CLI_OBJS = flashrom.o cli_classic.o cli_output.o print.o
+
+PROGRAMMER_OBJS = udelay.o programmer.o
+
+all: pciutils features $(PROGRAM)$(EXEC_SUFFIX)
+
+# Set the flashrom version string from the highest revision number
+# 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 := 1564
+
+RELEASE := 0.9.6.1
+VERSION := $(RELEASE)-r$(SVNVERSION)
+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
+
+# RayeR SPIPGM hardware support
+CONFIG_RAYER_SPI ?= yes
+
+# PonyProg2000 SPI hardware support
+CONFIG_PONY_SPI ?= yes
+
+# Always enable 3Com NICs for now.
+CONFIG_NIC3COM ?= yes
+
+# Enable NVIDIA graphics cards. Note: write and erase do not work properly.
+CONFIG_GFXNVIDIA ?= yes
+
+# 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_FT2232_SPI ?= yes
+
+# Always enable dummy tracing for now.
+CONFIG_DUMMY ?= yes
+
+# Always enable Dr. Kaiser for now.
+CONFIG_DRKAISER ?= yes
+
+# Always enable Realtek NICs for now.
+CONFIG_NICREALTEK ?= yes
+
+# Disable National Semiconductor NICs until support is complete and tested.
+CONFIG_NICNATSEMI ?= no
+
+# Always enable Intel NICs for now.
+CONFIG_NICINTEL ?= yes
+
+# Always enable SPI on Intel NICs for now.
+CONFIG_NICINTEL_SPI ?= yes
+
+# Always enable SPI on OGP cards for now.
+CONFIG_OGP_SPI ?= yes
+
+# Always enable Bus Pirate SPI for now.
+CONFIG_BUSPIRATE_SPI ?= yes
+
+# Disable Dediprog SF100 until support is complete and tested.
+CONFIG_DEDIPROG ?= no
+
+# Always enable Marvell SATA controllers for now.
+CONFIG_SATAMV ?= yes
+
+# Enable Linux spidev interface by default. We disable it on non-Linux targets.
+CONFIG_LINUX_SPI ?= yes
+
+# Disable wiki printing by default. It is only useful if you have wiki access.
+CONFIG_PRINT_WIKI ?= no
+
+# Bitbanging SPI infrastructure, default off unless needed.
+ifeq ($(CONFIG_RAYER_SPI), yes)
+override CONFIG_BITBANG_SPI = yes
+else
+ifeq ($(CONFIG_PONY_SPI), yes)
+override CONFIG_BITBANG_SPI = yes
+else
+ifeq ($(CONFIG_INTERNAL), yes)
+override CONFIG_BITBANG_SPI = yes
+else
+ifeq ($(CONFIG_NICINTEL_SPI), yes)
+override CONFIG_BITBANG_SPI = yes
+else
+ifeq ($(CONFIG_OGP_SPI), yes)
+override CONFIG_BITBANG_SPI = yes
+else
+CONFIG_BITBANG_SPI ?= no
+endif
+endif
+endif
+endif
+endif
+
+ifeq ($(CONFIG_INTERNAL), yes)
+FEATURE_CFLAGS += -D'CONFIG_INTERNAL=1'
+PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o
+ifeq ($(ARCH), x86)
+PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o wbsio_spi.o mcp6x_spi.o
+PROGRAMMER_OBJS += ichspi.o ich_descriptors.o
+else
+endif
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_SERPROG), yes)
+FEATURE_CFLAGS += -D'CONFIG_SERPROG=1'
+PROGRAMMER_OBJS += serprog.o
+NEED_SERIAL := yes
+NEED_NET := yes
+endif
+
+ifeq ($(CONFIG_RAYER_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_RAYER_SPI=1'
+PROGRAMMER_OBJS += rayer_spi.o
+# Actually, NEED_PCI is wrong. NEED_IOPORT_ACCESS would be more correct.
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_PONY_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_PONY_SPI=1'
+PROGRAMMER_OBJS += pony_spi.o
+NEED_SERIAL := yes
+endif
+
+ifeq ($(CONFIG_BITBANG_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_BITBANG_SPI=1'
+PROGRAMMER_OBJS += bitbang_spi.o
+endif
+
+ifeq ($(CONFIG_NIC3COM), yes)
+FEATURE_CFLAGS += -D'CONFIG_NIC3COM=1'
+PROGRAMMER_OBJS += nic3com.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_GFXNVIDIA), yes)
+FEATURE_CFLAGS += -D'CONFIG_GFXNVIDIA=1'
+PROGRAMMER_OBJS += gfxnvidia.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_SATASII), yes)
+FEATURE_CFLAGS += -D'CONFIG_SATASII=1'
+PROGRAMMER_OBJS += satasii.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_ATAHPT), yes)
+FEATURE_CFLAGS += -D'CONFIG_ATAHPT=1'
+PROGRAMMER_OBJS += atahpt.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_FT2232_SPI), 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'CONFIG_FT2232_SPI=1'")
+FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)")
+PROGRAMMER_OBJS += ft2232_spi.o
+endif
+
+ifeq ($(CONFIG_DUMMY), yes)
+FEATURE_CFLAGS += -D'CONFIG_DUMMY=1'
+PROGRAMMER_OBJS += dummyflasher.o
+endif
+
+ifeq ($(CONFIG_DRKAISER), yes)
+FEATURE_CFLAGS += -D'CONFIG_DRKAISER=1'
+PROGRAMMER_OBJS += drkaiser.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_NICREALTEK), yes)
+FEATURE_CFLAGS += -D'CONFIG_NICREALTEK=1'
+PROGRAMMER_OBJS += nicrealtek.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_NICNATSEMI), yes)
+FEATURE_CFLAGS += -D'CONFIG_NICNATSEMI=1'
+PROGRAMMER_OBJS += nicnatsemi.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_NICINTEL), yes)
+FEATURE_CFLAGS += -D'CONFIG_NICINTEL=1'
+PROGRAMMER_OBJS += nicintel.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_NICINTEL_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_NICINTEL_SPI=1'
+PROGRAMMER_OBJS += nicintel_spi.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_OGP_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_OGP_SPI=1'
+PROGRAMMER_OBJS += ogp_spi.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_BUSPIRATE_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_BUSPIRATE_SPI=1'
+PROGRAMMER_OBJS += buspirate_spi.o
+NEED_SERIAL := yes
+endif
+
+ifeq ($(CONFIG_DEDIPROG), yes)
+FEATURE_CFLAGS += -D'CONFIG_DEDIPROG=1'
+FEATURE_LIBS += -lusb
+PROGRAMMER_OBJS += dediprog.o
+endif
+
+ifeq ($(CONFIG_SATAMV), yes)
+FEATURE_CFLAGS += -D'CONFIG_SATAMV=1'
+PROGRAMMER_OBJS += satamv.o
+NEED_PCI := yes
+endif
+
+ifeq ($(CONFIG_LINUX_SPI), yes)
+# This is a totally ugly hack.
+FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "LINUX_SPI_SUPPORT := yes" .features && printf "%s" "-D'CONFIG_LINUX_SPI=1'")
+PROGRAMMER_OBJS += linux_spi.o
+endif
+
+ifeq ($(NEED_SERIAL), yes)
+LIB_OBJS += serial.o
+endif
+
+ifeq ($(NEED_NET), yes)
+ifeq ($(TARGET_OS), SunOS)
+LIBS += -lsocket
+endif
+endif
+
+ifeq ($(NEED_PCI), yes)
+CHECK_LIBPCI = yes
+FEATURE_CFLAGS += -D'NEED_PCI=1'
+PROGRAMMER_OBJS += pcidev.o physmap.o hwaccess.o
+ifeq ($(TARGET_OS), NetBSD)
+# The libpci we want is called libpciutils on NetBSD and needs NetBSD libpci.
+LIBS += -lpciutils -lpci
+# For (i386|x86_64)_iopl(2).
+LIBS += -l$(shell uname -p)
+else
+ifeq ($(TARGET_OS), DOS)
+# FIXME There needs to be a better way to do this
+LIBS += ../libpci/lib/libpci.a
+else
+LIBS += -lpci
+ifeq ($(TARGET_OS), OpenBSD)
+# For (i386|amd64)_iopl(2).
+LIBS += -l$(shell uname -m)
+endif
+endif
+endif
+endif
+
+ifeq ($(CONFIG_PRINT_WIKI), yes)
+FEATURE_CFLAGS += -D'CONFIG_PRINT_WIKI=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")
+
+LIBFLASHROM_OBJS = $(CHIP_OBJS) $(PROGRAMMER_OBJS) $(LIB_OBJS)
+OBJS = $(CLI_OBJS) $(LIBFLASHROM_OBJS)
+
+$(PROGRAM)$(EXEC_SUFFIX): $(OBJS)
+       $(CC) $(LDFLAGS) -o $(PROGRAM)$(EXEC_SUFFIX) $(OBJS) $(FEATURE_LIBS) $(LIBS)
+
+libflashrom.a: $(LIBFLASHROM_OBJS)
+       $(AR) rcs $@ $^
+       $(RANLIB) $@
+
+# TAROPTIONS reduces information leakage from the packager's system.
+# If other tar programs support command line arguments for setting uid/gid of
+# stored files, they can be handled here as well.
+TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root --group=root")
+
+%.o: %.c .features
+       $(CC) -MMD $(CFLAGS) $(CPPFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) -o $@ -c $<
+
+# Make sure to add all names of generated binaries here.
+# This includes all frontends and libflashrom.
+# We don't use EXEC_SUFFIX here because we want to clean everything.
+clean:
+       rm -f $(PROGRAM) $(PROGRAM).exe libflashrom.a *.o *.d
+
+distclean: clean
+       rm -f .features .libdeps
+
+strip: $(PROGRAM)$(EXEC_SUFFIX)
+       $(STRIP) $(STRIP_ARGS) $(PROGRAM)$(EXEC_SUFFIX)
+
+# to define test programs we use verbatim variables, which get exported
+# to environment variables and are referenced with $$<varname> later
+
+define COMPILER_TEST
+int main(int argc, char **argv)
+{
+       (void) argc;
+       (void) argv;
+       return 0;
+}
+endef
+export COMPILER_TEST
+
+compiler: featuresavailable
+       @printf "Checking for a C compiler... "
+       @echo "$$COMPILER_TEST" > .test.c
+       @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .test.c -o .test$(EXEC_SUFFIX) >/dev/null 2>&1 &&       \
+               echo "found." || ( echo "not found."; \
+               rm -f .test.c .test$(EXEC_SUFFIX); exit 1)
+       @rm -f .test.c .test$(EXEC_SUFFIX)
+       @printf "Target arch is "
+       @# FreeBSD wc will output extraneous whitespace.
+       @echo $(ARCH)|wc -w|grep -q '^[[:blank:]]*1[[:blank:]]*$$' ||   \
+               ( echo "unknown. Aborting."; exit 1)
+       @printf "%s\n" '$(ARCH)'
+       @printf "Target OS is "
+       @# FreeBSD wc will output extraneous whitespace.
+       @echo $(TARGET_OS)|wc -w|grep -q '^[[:blank:]]*1[[:blank:]]*$$' ||      \
+               ( echo "unknown. Aborting."; exit 1)
+       @printf "%s\n" '$(TARGET_OS)'
+
+define LIBPCI_TEST
+/* Avoid a failing test due to libpci header symbol shadowing breakage */
+#define index shadow_workaround_index
+#include <pci/pci.h>
+struct pci_access *pacc;
+int main(int argc, char **argv)
+{
+       (void) argc;
+       (void) argv;
+       pacc = pci_alloc();
+       return 0;
+}
+endef
+export LIBPCI_TEST
+
+ifeq ($(CHECK_LIBPCI), yes)
+pciutils: compiler
+       @printf "Checking for libpci headers... "
+       @echo "$$LIBPCI_TEST" > .test.c
+       @$(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$(EXEC_SUFFIX) $(LIBS) >/dev/null 2>&1 &&                             \
+               echo "yes." || ( echo "no.";                                                    \
+               printf "Checking if libz+libpci are present and sufficient..."; \
+               $(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(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$(EXEC_SUFFIX); exit 1) )
+       @rm -f .test.c .test.o .test$(EXEC_SUFFIX)
+else
+pciutils: compiler
+       @printf "" > .libdeps
+endif
+
+.features: features
+
+# If a user does not explicitly request a non-working feature, we should
+# silently disable it. However, if a non-working (does not compile) feature
+# is explicitly requested, we should bail out with a descriptive error message.
+ifeq ($(UNSUPPORTED_FEATURES), )
+featuresavailable:
+else
+featuresavailable:
+       @echo "The following features are unavailable on your machine: $(UNSUPPORTED_FEATURES)"
+       @false
+endif
+
+define FTDI_TEST
+#include <ftdi.h>
+struct ftdi_context *ftdic = NULL;
+int main(int argc, char **argv)
+{
+       (void) argc;
+       (void) argv;
+       return ftdi_init(ftdic);
+}
+endef
+export FTDI_TEST
+
+define UTSNAME_TEST
+#include <sys/utsname.h>
+struct utsname osinfo;
+int main(int argc, char **argv)
+{
+       (void) argc;
+       (void) argv;
+       uname (&osinfo);
+       return 0;
+}
+endef
+export UTSNAME_TEST
+
+define LINUX_SPI_TEST
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+int main(int argc, char **argv)
+{
+       (void) argc;
+       (void) argv;
+       return 0;
+}
+endef
+export LINUX_SPI_TEST
+
+features: compiler
+       @echo "FEATURES := yes" > .features.tmp
+ifeq ($(CONFIG_FT2232_SPI), yes)
+       @printf "Checking for FTDI support... "
+       @echo "$$FTDI_TEST" > .featuretest.c
+       @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 &&     \
+               ( echo "found."; echo "FTDISUPPORT := yes" >> .features.tmp ) ||        \
+               ( echo "not found."; echo "FTDISUPPORT := no" >> .features.tmp )
+endif
+ifeq ($(CONFIG_LINUX_SPI), yes)
+       @printf "Checking if Linux SPI headers are present... "
+       @echo "$$LINUX_SPI_TEST" > .featuretest.c
+       @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) >/dev/null 2>&1 && \
+               ( echo "yes."; echo "LINUX_SPI_SUPPORT := yes" >> .features.tmp ) ||    \
+               ( echo "no."; echo "LINUX_SPI_SUPPORT := no" >> .features.tmp )
+endif
+       @printf "Checking for utsname support... "
+       @echo "$$UTSNAME_TEST" > .featuretest.c
+       @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) >/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$(EXEC_SUFFIX)
+
+install: $(PROGRAM)$(EXEC_SUFFIX)
+       mkdir -p $(DESTDIR)$(PREFIX)/sbin
+       mkdir -p $(DESTDIR)$(MANDIR)/man8
+       $(INSTALL) -m 0755 $(PROGRAM)$(EXEC_SUFFIX) $(DESTDIR)$(PREFIX)/sbin
+       $(INSTALL) -m 0644 $(PROGRAM).8 $(DESTDIR)$(MANDIR)/man8
+
+export:
+       @rm -rf $(EXPORTDIR)/flashrom-$(RELEASENAME)
+       @svn export -r BASE . $(EXPORTDIR)/flashrom-$(RELEASENAME)
+       @sed "s/^SVNVERSION.*/SVNVERSION := $(SVNVERSION)/" Makefile >$(EXPORTDIR)/flashrom-$(RELEASENAME)/Makefile
+       @LC_ALL=C svn log >$(EXPORTDIR)/flashrom-$(RELEASENAME)/ChangeLog
+       @echo Exported $(EXPORTDIR)/flashrom-$(RELEASENAME)/
+
+tarball: export
+       @tar cjf $(EXPORTDIR)/flashrom-$(RELEASENAME).tar.bz2 -C $(EXPORTDIR)/ $(TAROPTIONS) flashrom-$(RELEASENAME)/
+       @rm -rf $(EXPORTDIR)/flashrom-$(RELEASENAME)
+       @echo Created $(EXPORTDIR)/flashrom-$(RELEASENAME).tar.bz2
+
+djgpp-dos: clean
+       make CC=i586-pc-msdosdjgpp-gcc STRIP=i586-pc-msdosdjgpp-strip
+libpayload: clean
+       make CC="CC=i386-elf-gcc lpgcc" AR=i386-elf-ar RANLIB=i386-elf-ranlib
+
+.PHONY: all clean distclean compiler pciutils features export tarball dos featuresavailable
+
+-include $(OBJS:.o=.d)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f88b3b5
--- /dev/null
+++ b/README
@@ -0,0 +1,159 @@
+-------------------------------------------------------------------------------
+flashrom README
+-------------------------------------------------------------------------------
+
+flashrom is a utility for detecting, reading, writing, verifying and erasing
+flash chips. It is often used to flash BIOS/EFI/coreboot/firmware images
+in-system using a supported mainboard, but it also supports flashing of network
+cards (NICs), SATA controller cards, and other external devices which can
+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.
+
+Do not use flashrom on laptops! The embedded controller (EC) present in many
+laptops interacts badly with any flash attempts and can brick your laptop
+permanently.
+
+Please make a backup of your flash chip before writing to it.
+
+Please see the flashrom(8) manpage.
+
+
+Packaging
+---------
+
+To package flashrom and remove dependencies on subversion, either use
+make export
+or
+make tarball
+
+make export will export all flashrom files from the subversion repository at
+revision BASE into a directory named $EXPORTDIR/flashrom-$VERSION-r$SVNREVISION
+and will additionally modify the Makefile in that directory to contain the svn
+revision of the exported tree.
+
+make tarball will simply tar up the result of make export and gzip compress it.
+
+The snapshot tarballs are the result of make tarball and require no further
+processing.
+
+
+Build Instructions
+------------------
+
+To build flashrom you need to install the following software:
+
+ * pciutils+libpci (if you want support for mainboard or PCI device flashing)
+ * libusb (if you want FT2232 or Dediprog support)
+ * libftdi (if you want FT2232 support)
+
+Linux et al:
+
+ * pciutils / libpci
+ * pciutils-devel / pciutils-dev / libpci-dev
+ * zlib-devel / zlib1g-dev (needed if libpci was compiled with libz support)
+
+On FreeBSD, you need the following ports:
+
+ * devel/gmake
+ * devel/libpci
+
+On OpenBSD, you need the following ports:
+
+ * devel/gmake
+ * sysutils/pciutils
+
+To compile on Linux, use:
+
+ make
+
+To compile on FreeBSD, use:
+
+ gmake
+
+To compile on Nexenta, use:
+
+ make
+
+To compile on Solaris, use:
+
+ gmake LDFLAGS="-L$pathtolibpci" CC="gcc -I$pathtopciheaders" CFLAGS=-O2
+
+To compile on NetBSD or DragonFly BSD, use:
+
+ ln -s /usr/pkg/include/pciutils pci
+ gmake CPPFLAGS="-I. -I/usr/pkg/include" \
+       LDFLAGS="-L/usr/pkg/lib -Wl,-rpath-link,/usr/pkg/lib"
+
+To compile on OpenBSD, use:
+
+ gmake
+
+To compile and run on Darwin/Mac OS X:
+
+ Install DirectHW from coresystems GmbH.
+ DirectHW is available at http://www.coresystems.de/en/directhw .
+
+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-4.3.2-8ap.i686.rpm
+ djcrx-2.04pre_20090725-13ap.i386.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 and unpack
+ http://homer.rice.edu/~sandmann/cwsdpmi/csdpmi7b.zip and make sure
+ CWSDPMI.EXE is in the current directory.
+
+Processor architecture dependent features:
+
+ On non-x86 architectures you have to disable a few programmers because they
+ use port-based I/O which is not directly available on non-x86. Please add
+ CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_ATAHPT=no CONFIG_NICREALTEK=no \
+ CONFIG_NICNATSEMI=no
+ as parameters to the "make" invocation.
+ Besides that, the internal programmer is only supported on x86 and MIPS. On
+ other architectures, please add
+ CONFIG_INTERNAL=no
+ as parameter to the "make" invocation.
+
+Installation
+------------
+
+In order to install flashrom and the manpage into /usr/local, type:
+
+ make install
+
+For installation in a different directory use DESTDIR, e.g. like this:
+
+ make DESTDIR=/usr install
+
+If you have insufficient permissions for the destination directory, use sudo
+by adding sudo in front of the commands above.
+
+
+Contact
+-------
+
+The official flashrom website is:
+
+  http://www.flashrom.org/
+
+The IRC channel is
+
+  #flashrom at irc.freenode.net
+
+The mailing list address is
+
+  flashrom@flashrom.org
diff --git a/a25.c b/a25.c
new file mode 100644 (file)
index 0000000..8c38f87
--- /dev/null
+++ b/a25.c
@@ -0,0 +1,106 @@
+/*
+ * 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 "flash.h"
+#include "chipdrivers.h"
+#include "spi.h"
+
+/* Prettyprint the status register. Works for AMIC A25L series. */
+
+static void spi_prettyprint_status_register_amic_a25_srwd(uint8_t status)
+{
+       msg_cdbg("Chip status register: Status Register Write Disable "
+                    "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not ");
+}
+
+int spi_prettyprint_status_register_amic_a25l05p(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_amic_a25_srwd(status);
+       spi_prettyprint_status_register_bit(status, 6);
+       spi_prettyprint_status_register_bit(status, 5);
+       spi_prettyprint_status_register_bit(status, 4);
+       spi_prettyprint_status_register_bp(status, 1);
+       spi_prettyprint_status_register_welwip(status);
+       return 0;
+}
+
+int spi_prettyprint_status_register_amic_a25l40p(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_amic_a25_srwd(status);
+       spi_prettyprint_status_register_bit(status, 6);
+       spi_prettyprint_status_register_bit(status, 5);
+       spi_prettyprint_status_register_bp(status, 2);
+       spi_prettyprint_status_register_welwip(status);
+       return 0;
+}
+
+int spi_prettyprint_status_register_amic_a25l032(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_amic_a25_srwd(status);
+       msg_cdbg("Chip status register: Sector Protect Size (SEC) "
+                "is %i KB\n", (status & (1 << 6)) ? 4 : 64);
+       msg_cdbg("Chip status register: Top/Bottom (TB) "
+                "is %s\n", (status & (1 << 5)) ? "bottom" : "top");
+       spi_prettyprint_status_register_bp(status, 2);
+       spi_prettyprint_status_register_welwip(status);
+       msg_cdbg("Chip status register 2 is NOT decoded!\n");
+       return 0;
+}
+
+int spi_prettyprint_status_register_amic_a25lq032(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_amic_a25_srwd(status);
+       msg_cdbg("Chip status register: Sector Protect Size (SEC) "
+                "is %i KB\n", (status & (1 << 6)) ? 4 : 64);
+       msg_cdbg("Chip status register: Top/Bottom (TB) "
+                "is %s\n", (status & (1 << 5)) ? "bottom" : "top");
+       spi_prettyprint_status_register_bp(status, 2);
+       spi_prettyprint_status_register_welwip(status);
+       msg_cdbg("Chip status register 2 is NOT decoded!\n");
+       return 0;
+}
+
+/* FIXME: spi_disable_blockprotect is incorrect but works fine for chips using
+ * spi_prettyprint_status_register_amic_a25l05p or
+ * spi_prettyprint_status_register_amic_a25l40p.
+ * FIXME: spi_disable_blockprotect is incorrect and will fail for chips using
+ * spi_prettyprint_status_register_amic_a25l032 or
+ * spi_prettyprint_status_register_amic_a25lq032 if those have locks controlled
+ * by the second status register.
+ */
diff --git a/arch.h b/arch.h
new file mode 100644 (file)
index 0000000..f3f3b0d
--- /dev/null
+++ b/arch.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011 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 CPU architecture checking.
+ */
+
+#if defined (__i386__) || defined (__x86_64__)
+#define __FLASHROM_ARCH__ "x86"
+#elif defined (__mips) || defined (__mips__) || defined (_mips) || defined (mips)
+#define __FLASHROM_ARCH__ "mips"
+#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__)
+#define __FLASHROM_ARCH__ "ppc"
+#elif defined(__arm__)
+#define __FLASHROM_ARCH__ "arm"
+#endif
+__FLASHROM_ARCH__
diff --git a/at25.c b/at25.c
new file mode 100644 (file)
index 0000000..817e769
--- /dev/null
+++ b/at25.c
@@ -0,0 +1,281 @@
+/*
+ * 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 "flash.h"
+#include "chipdrivers.h"
+#include "spi.h"
+
+/* Prettyprint the status register. Works for Atmel A25/A26 series. */
+
+static void spi_prettyprint_status_register_atmel_at25_wpen(uint8_t status)
+{
+       msg_cdbg("Chip status register: Write Protect Enable (WPEN) "
+                "is %sset\n", (status & (1 << 7)) ? "" : "not ");
+}
+
+static void spi_prettyprint_status_register_atmel_at25_srpl(uint8_t status)
+{
+       msg_cdbg("Chip status register: Sector Protection Register Lock (SRPL) "
+                "is %sset\n", (status & (1 << 7)) ? "" : "not ");
+}
+
+static void spi_prettyprint_status_register_atmel_at25_epewpp(uint8_t status)
+{
+       msg_cdbg("Chip status register: Erase/Program Error (EPE) "
+                "is %sset\n", (status & (1 << 5)) ? "" : "not ");
+       msg_cdbg("Chip status register: WP# pin (WPP) "
+                "is %sasserted\n", (status & (1 << 4)) ? "not " : "");
+}
+
+static void spi_prettyprint_status_register_atmel_at25_swp(uint8_t status)
+{
+       msg_cdbg("Chip status register: Software Protection Status (SWP): ");
+       switch (status & (3 << 2)) {
+       case 0x0 << 2:
+               msg_cdbg("no sectors are protected\n");
+               break;
+       case 0x1 << 2:
+               msg_cdbg("some sectors are protected\n");
+               /* FIXME: Read individual Sector Protection Registers. */
+               break;
+       case 0x3 << 2:
+               msg_cdbg("all sectors are protected\n");
+               break;
+       default:
+               msg_cdbg("reserved for future use\n");
+               break;
+       }
+}
+
+int spi_prettyprint_status_register_at25df(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_atmel_at25_srpl(status);
+       spi_prettyprint_status_register_bit(status, 6);
+       spi_prettyprint_status_register_atmel_at25_epewpp(status);
+       spi_prettyprint_status_register_atmel_at25_swp(status);
+       spi_prettyprint_status_register_welwip(status);
+       return 0;
+}
+
+int spi_prettyprint_status_register_at25df_sec(struct flashctx *flash)
+{
+       /* FIXME: We should check the security lockdown. */
+       msg_cdbg("Ignoring security lockdown (if present)\n");
+       msg_cdbg("Ignoring status register byte 2\n");
+       return spi_prettyprint_status_register_at25df(flash);
+}
+
+int spi_prettyprint_status_register_at25f(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_atmel_at25_srpl(status);
+       spi_prettyprint_status_register_bit(status, 6);
+       spi_prettyprint_status_register_atmel_at25_epewpp(status);
+       spi_prettyprint_status_register_bit(status, 3);
+       spi_prettyprint_status_register_bp(status, 0);
+       spi_prettyprint_status_register_welwip(status);
+       return 0;
+}
+
+int spi_prettyprint_status_register_at25fs010(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_atmel_at25_wpen(status);
+       msg_cdbg("Chip status register: Bit 6 / Block Protect 4 (BP4) is "
+                "%sset\n", (status & (1 << 6)) ? "" : "not ");
+       msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is "
+                "%sset\n", (status & (1 << 5)) ? "" : "not ");
+       spi_prettyprint_status_register_bit(status, 4);
+       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 ");
+       /* FIXME: Pretty-print detailed sector protection status. */
+       spi_prettyprint_status_register_welwip(status);
+       return 0;
+}
+
+int spi_prettyprint_status_register_at25fs040(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_atmel_at25_wpen(status);
+       spi_prettyprint_status_register_bp(status, 4);
+       /* FIXME: Pretty-print detailed sector protection status. */
+       spi_prettyprint_status_register_welwip(status);
+       return 0;
+}
+
+int spi_prettyprint_status_register_atmel_at26df081a(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       msg_cdbg("Chip status register is %02x\n", status);
+
+       spi_prettyprint_status_register_atmel_at25_srpl(status);
+       msg_cdbg("Chip status register: Sequential Program Mode Status (SPM) "
+                "is %sset\n", (status & (1 << 6)) ? "" : "not ");
+       spi_prettyprint_status_register_atmel_at25_epewpp(status);
+       spi_prettyprint_status_register_atmel_at25_swp(status);
+       spi_prettyprint_status_register_welwip(status);
+       return 0;
+}
+
+int spi_disable_blockprotect_at25df(struct flashctx *flash)
+{
+       uint8_t status;
+       int result;
+
+       status = spi_read_status_register(flash);
+       /* If block protection is disabled, stop here. */
+       if ((status & (3 << 2)) == 0)
+               return 0;
+
+       msg_cdbg("Some block protection in effect, disabling... ");
+       if (status & (1 << 7)) {
+               msg_cdbg("Need to disable Sector Protection Register Lock\n");
+               if ((status & (1 << 4)) == 0) {
+                       msg_cerr("WP# pin is active, disabling "
+                                "write protection is impossible.\n");
+                       return 1;
+               }
+               /* All bits except bit 7 (SPRL) are readonly. */
+               result = spi_write_status_register(flash, status & ~(1 << 7));
+               if (result) {
+                       msg_cerr("spi_write_status_register failed.\n");
+                       return result;
+               }
+               
+       }
+       /* Global unprotect. Make sure to mask SPRL as well. */
+       result = spi_write_status_register(flash, status & ~0xbc);
+       if (result) {
+               msg_cerr("spi_write_status_register failed.\n");
+               return result;
+       }
+       status = spi_read_status_register(flash);
+       if ((status & (3 << 2)) != 0) {
+               msg_cerr("Block protection could not be disabled!\n");
+               return 1;
+       }
+       msg_cdbg("done.\n");
+       return 0;
+}
+
+int spi_disable_blockprotect_at25df_sec(struct flashctx *flash)
+{
+       /* FIXME: We should check the security lockdown. */
+       msg_cinfo("Ignoring security lockdown (if present)\n");
+       return spi_disable_blockprotect_at25df(flash);
+}
+
+int spi_disable_blockprotect_at25f(struct flashctx *flash)
+{
+       /* spi_disable_blockprotect_at25df is not really the right way to do
+        * this, but the side effects of said function work here as well.
+        */
+       return spi_disable_blockprotect_at25df(flash);
+}
+
+int spi_disable_blockprotect_at25fs010(struct flashctx *flash)
+{
+       uint8_t status;
+       int result;
+
+       status = spi_read_status_register(flash);
+       /* If block protection is disabled, stop here. */
+       if ((status & 0x6c) == 0)
+               return 0;
+
+       msg_cdbg("Some block protection in effect, disabling... ");
+       if (status & (1 << 7)) {
+               msg_cdbg("Need to disable Status Register Write Protect\n");
+               /* Clear bit 7 (WPEN). */
+               result = spi_write_status_register(flash, status & ~(1 << 7));
+               if (result) {
+                       msg_cerr("spi_write_status_register failed.\n");
+                       return result;
+               }
+       }
+       /* Global unprotect. Make sure to mask WPEN as well. */
+       result = spi_write_status_register(flash, status & ~0xec);
+       if (result) {
+               msg_cerr("spi_write_status_register failed.\n");
+               return result;
+       }
+       status = spi_read_status_register(flash);
+       if ((status & 0x6c) != 0) {
+               msg_cerr("Block protection could not be disabled!\n");
+               return 1;
+       }
+       msg_cdbg("done.\n");
+       return 0;
+}
+
+int spi_disable_blockprotect_at25fs040(struct flashctx *flash)
+{
+       uint8_t status;
+       int result;
+
+       status = spi_read_status_register(flash);
+       /* If block protection is disabled, stop here. */
+       if ((status & 0x7c) == 0)
+               return 0;
+
+       msg_cdbg("Some block protection in effect, disabling... ");
+       if (status & (1 << 7)) {
+               msg_cdbg("Need to disable Status Register Write Protect\n");
+               /* Clear bit 7 (WPEN). */
+               result = spi_write_status_register(flash, status & ~(1 << 7));
+               if (result) {
+                       msg_cerr("spi_write_status_register failed.\n");
+                       return result;
+               }
+       }
+       /* Global unprotect. Make sure to mask WPEN as well. */
+       result = spi_write_status_register(flash, status & ~0xfc);
+       if (result) {
+               msg_cerr("spi_write_status_register failed.\n");
+               return result;
+       }
+       status = spi_read_status_register(flash);
+       if ((status & 0x7c) != 0) {
+               msg_cerr("Block protection could not be disabled!\n");
+               return 1;
+       }
+       msg_cdbg("done.\n");
+       return 0;
+}
diff --git a/atahpt.c b/atahpt.c
new file mode 100644 (file)
index 0000000..f410fe4
--- /dev/null
+++ b/atahpt.c
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define BIOS_ROM_ADDR          0x90
+#define BIOS_ROM_DATA          0x94
+
+#define REG_FLASH_ACCESS       0x58
+
+#define PCI_VENDOR_ID_HPT      0x1103
+
+const 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"},
+
+       {},
+};
+
+static void atahpt_chip_writeb(const struct flashctx *flash, uint8_t val,
+                              chipaddr addr);
+static uint8_t atahpt_chip_readb(const struct flashctx *flash,
+                                const chipaddr addr);
+static const struct par_programmer par_programmer_atahpt = {
+               .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,
+};
+
+static int atahpt_shutdown(void *data)
+{
+       /* Flash access is disabled automatically by PCI restore. */
+       pci_cleanup(pacc);
+       return 0;
+}
+
+int atahpt_init(void)
+{
+       uint32_t reg32;
+
+       if (rget_io_perms())
+               return 1;
+
+       io_base_addr = pcidev_init(PCI_BASE_ADDRESS_4, ata_hpt);
+
+       /* Enable flash access. */
+       reg32 = pci_read_long(pcidev_dev, REG_FLASH_ACCESS);
+       reg32 |= (1 << 24);
+       rpci_write_long(pcidev_dev, REG_FLASH_ACCESS, reg32);
+
+       if (register_shutdown(atahpt_shutdown, NULL))
+               return 1;
+
+       register_par_programmer(&par_programmer_atahpt, BUS_PARALLEL);
+
+       return 0;
+}
+
+static void atahpt_chip_writeb(const struct flashctx *flash, uint8_t val,
+                              chipaddr addr)
+{
+       OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
+       OUTB(val, io_base_addr + BIOS_ROM_DATA);
+}
+
+static uint8_t atahpt_chip_readb(const struct flashctx *flash,
+                                const chipaddr addr)
+{
+       OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
+       return INB(io_base_addr + BIOS_ROM_DATA);
+}
+
+#else
+#error PCI port I/O access is not supported on this architecture yet.
+#endif
diff --git a/bitbang_spi.c b/bitbang_spi.c
new file mode 100644 (file)
index 0000000..11d2de1
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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; 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "flash.h"
+#include "programmer.h"
+#include "spi.h"
+
+/* Note that CS# is active low, so val=0 means the chip is active. */
+static void bitbang_spi_set_cs(const const struct bitbang_spi_master *master, int val)
+{
+       master->set_cs(val);
+}
+
+static void bitbang_spi_set_sck(const const struct bitbang_spi_master *master, int val)
+{
+       master->set_sck(val);
+}
+
+static void bitbang_spi_set_mosi(const const struct bitbang_spi_master *master, int val)
+{
+       master->set_mosi(val);
+}
+
+static int bitbang_spi_get_miso(const const struct bitbang_spi_master *master)
+{
+       return master->get_miso();
+}
+
+static void bitbang_spi_request_bus(const const struct bitbang_spi_master *master)
+{
+       if (master->request_bus)
+               master->request_bus();
+}
+
+static void bitbang_spi_release_bus(const const struct bitbang_spi_master *master)
+{
+       if (master->release_bus)
+               master->release_bus();
+}
+
+static int bitbang_spi_send_command(struct flashctx *flash,
+                                   unsigned int writecnt, unsigned int readcnt,
+                                   const unsigned char *writearr,
+                                   unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_bitbang = {
+       .type           = SPI_CONTROLLER_BITBANG,
+       .max_data_read  = MAX_DATA_READ_UNLIMITED,
+       .max_data_write = MAX_DATA_WRITE_UNLIMITED,
+       .command        = bitbang_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = default_spi_read,
+       .write_256      = default_spi_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+#if 0 // until it is needed
+static int bitbang_spi_shutdown(const struct bitbang_spi_master *master)
+{
+       /* FIXME: Run bitbang_spi_release_bus here or per command? */
+       return 0;
+}
+#endif
+
+int bitbang_spi_init(const struct bitbang_spi_master *master)
+{
+       struct spi_programmer pgm = spi_programmer_bitbang;
+       /* BITBANG_SPI_INVALID is 0, so if someone forgot to initialize ->type,
+        * we catch it here. Same goes for missing initialization of bitbanging
+        * functions.
+        */
+       if (!master || master->type == BITBANG_SPI_INVALID || !master->set_cs ||
+           !master->set_sck || !master->set_mosi || !master->get_miso ||
+           (master->request_bus && !master->release_bus) ||
+           (!master->request_bus && master->release_bus)) {
+               msg_perr("Incomplete SPI bitbang master setting!\n"
+                        "Please report a bug at flashrom@flashrom.org\n");
+               return ERROR_FLASHROM_BUG;
+       }
+
+       pgm.data = master;
+       register_spi_programmer(&pgm);
+
+       /* Only mess with the bus if we're sure nobody else uses it. */
+       bitbang_spi_request_bus(master);
+       bitbang_spi_set_cs(master, 1);
+       bitbang_spi_set_sck(master, 0);
+       bitbang_spi_set_mosi(master, 0);
+       /* FIXME: Release SPI bus here and request it again for each command or
+        * don't release it now and only release it on programmer shutdown?
+        */
+       bitbang_spi_release_bus(master);
+       return 0;
+}
+
+static uint8_t bitbang_spi_rw_byte(const struct bitbang_spi_master *master,
+                                  uint8_t val)
+{
+       uint8_t ret = 0;
+       int i;
+
+       for (i = 7; i >= 0; i--) {
+               bitbang_spi_set_mosi(master, (val >> i) & 1);
+               programmer_delay(master->half_period);
+               bitbang_spi_set_sck(master, 1);
+               ret <<= 1;
+               ret |= bitbang_spi_get_miso(master);
+               programmer_delay(master->half_period);
+               bitbang_spi_set_sck(master, 0);
+       }
+       return ret;
+}
+
+static int bitbang_spi_send_command(struct flashctx *flash,
+                                   unsigned int writecnt, unsigned int readcnt,
+                                   const unsigned char *writearr,
+                                   unsigned char *readarr)
+{
+       int i;
+       const struct bitbang_spi_master *master = flash->pgm->spi.data;
+
+       /* FIXME: Run bitbang_spi_request_bus here or in programmer init?
+        * Requesting and releasing the SPI bus is handled in here to allow the
+        * programmer to use its own SPI engine for native accesses.
+        */
+       bitbang_spi_request_bus(master);
+       bitbang_spi_set_cs(master, 0);
+       for (i = 0; i < writecnt; i++)
+               bitbang_spi_rw_byte(master, writearr[i]);
+       for (i = 0; i < readcnt; i++)
+               readarr[i] = bitbang_spi_rw_byte(master, 0);
+
+       programmer_delay(master->half_period);
+       bitbang_spi_set_cs(master, 1);
+       programmer_delay(master->half_period);
+       /* FIXME: Run bitbang_spi_release_bus here or in programmer init? */
+       bitbang_spi_release_bus(master);
+
+       return 0;
+}
diff --git a/board_enable.c b/board_enable.c
new file mode 100644 (file)
index 0000000..3c791b1
--- /dev/null
@@ -0,0 +1,2629 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
+ * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2007-2009 Luc Verhaegen <libv@skynet.be>
+ * 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; 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 board specific flash enables.
+ */
+
+#include <string.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * Helper functions for many Winbond Super I/Os of the W836xx range.
+ */
+/* Enter extended functions */
+void w836xx_ext_enter(uint16_t port)
+{
+       OUTB(0x87, port);
+       OUTB(0x87, port);
+}
+
+/* Leave extended functions */
+void w836xx_ext_leave(uint16_t port)
+{
+       OUTB(0xAA, port);
+}
+
+/* Generic Super I/O helper functions */
+uint8_t sio_read(uint16_t port, uint8_t reg)
+{
+       OUTB(reg, port);
+       return INB(port + 1);
+}
+
+void sio_write(uint16_t port, uint8_t reg, uint8_t data)
+{
+       OUTB(reg, port);
+       OUTB(data, port + 1);
+}
+
+void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask)
+{
+       uint8_t tmp;
+
+       OUTB(reg, port);
+       tmp = INB(port + 1) & ~mask;
+       OUTB(tmp | (data & mask), port + 1);
+}
+
+/* Winbond W83697 documentation indicates that the index register has to be written for each access. */
+void sio_mask_alzheimer(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask)
+{
+       uint8_t tmp;
+
+       OUTB(reg, port);
+       tmp = INB(port + 1) & ~mask;
+       OUTB(reg, port);
+       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:
+               msg_pdbg("Unhandled Super I/O type!\n");
+               ret = -1;
+               break;
+       }
+       return ret;
+}
+#endif
+
+/*
+ * SMSC FDC37B787: Raise GPIO50
+ */
+static int fdc37b787_gpio50_raise(uint16_t port)
+{
+       uint8_t id, val;
+
+       OUTB(0x55, port);       /* enter conf mode */
+       id = sio_read(port, 0x20);
+       if (id != 0x44) {
+               msg_perr("\nERROR: FDC37B787: Wrong ID 0x%02X.\n", id);
+               OUTB(0xAA, port); /* leave conf mode */
+               return -1;
+       }
+
+       sio_write(port, 0x07, 0x08);    /* Select Aux I/O subdevice */
+
+       val = sio_read(port, 0xC8);     /* GP50 */
+       if ((val & 0x1B) != 0x10)       /* output, no invert, GPIO */
+       {
+               msg_perr("\nERROR: GPIO50 mode 0x%02X unexpected.\n", val);
+               OUTB(0xAA, port);
+               return -1;
+       }
+
+       sio_mask(port, 0xF9, 0x01, 0x01);
+
+       OUTB(0xAA, port);               /* Leave conf mode */
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - Nokia IP530: Intel 440BX + PIIX4 + FDC37B787
+ */
+static int fdc37b787_gpio50_raise_3f0(void)
+{
+       return fdc37b787_gpio50_raise(0x3f0);
+}
+
+struct winbond_mux {
+       uint8_t reg;            /* 0 if the corresponding pin is not muxed */
+       uint8_t data;           /* reg/data/mask may be directly ... */
+       uint8_t mask;           /* ... passed to sio_mask */
+};
+
+struct winbond_port {
+       const struct winbond_mux *mux; /* NULL or pointer to mux info for the 8 bits */
+       uint8_t ldn;            /* LDN this GPIO register is located in */
+       uint8_t enable_bit;     /* bit in 0x30 of that LDN to enable 
+                                  the GPIO port */
+       uint8_t base;           /* base register in that LDN for the port */
+};
+
+struct winbond_chip {
+       uint8_t device_id;      /* reg 0x20 of the expected w83626x */
+       uint8_t gpio_port_count;
+       const struct winbond_port *port;
+};
+
+
+#define UNIMPLEMENTED_PORT {NULL, 0, 0, 0}
+
+enum winbond_id {
+       WINBOND_W83627HF_ID = 0x52,
+       WINBOND_W83627EHF_ID = 0x88,
+       WINBOND_W83627THF_ID = 0x82,
+       WINBOND_W83697HF_ID = 0x60,
+};
+
+static const struct winbond_mux w83627hf_port2_mux[8] = {
+       {0x2A, 0x01, 0x01},     /* or MIDI */
+       {0x2B, 0x80, 0x80},     /* or SPI */
+       {0x2B, 0x40, 0x40},     /* or SPI */
+       {0x2B, 0x20, 0x20},     /* or power LED */
+       {0x2B, 0x10, 0x10},     /* or watchdog */
+       {0x2B, 0x08, 0x08},     /* or infra red */
+       {0x2B, 0x04, 0x04},     /* or infra red */
+       {0x2B, 0x03, 0x03}      /* or IRQ1 input */
+};
+
+static const struct winbond_port w83627hf[3] = {
+       UNIMPLEMENTED_PORT,
+       {w83627hf_port2_mux, 0x08, 0, 0xF0},
+       UNIMPLEMENTED_PORT,
+};
+
+static const struct winbond_mux w83627ehf_port2_mux[8] = {
+       {0x29, 0x06, 0x02},     /* or MIDI */
+       {0x29, 0x06, 0x02},
+       {0x24, 0x02, 0x00},     /* or SPI ROM interface */
+       {0x24, 0x02, 0x00},
+       {0x2A, 0x01, 0x01},     /* or keyboard/mouse interface */
+       {0x2A, 0x01, 0x01},
+       {0x2A, 0x01, 0x01},
+       {0x2A, 0x01, 0x01},
+};
+
+static const struct winbond_port w83627ehf[6] = {
+       UNIMPLEMENTED_PORT,
+       {w83627ehf_port2_mux, 0x09, 0, 0xE3},
+       UNIMPLEMENTED_PORT,
+       UNIMPLEMENTED_PORT,
+       UNIMPLEMENTED_PORT,
+       UNIMPLEMENTED_PORT,
+};
+
+static const struct winbond_mux w83627thf_port4_mux[8] = {
+       {0x2D, 0x01, 0x01},     /* or watchdog or VID level strap */
+       {0x2D, 0x02, 0x02},     /* or resume reset */
+       {0x2D, 0x04, 0x04},     /* or S3 input */
+       {0x2D, 0x08, 0x08},     /* or PSON# */
+       {0x2D, 0x10, 0x10},     /* or PWROK */
+       {0x2D, 0x20, 0x20},     /* or suspend LED */
+       {0x2D, 0x40, 0x40},     /* or panel switch input */
+       {0x2D, 0x80, 0x80},     /* or panel switch output */
+};
+
+static const struct winbond_port w83627thf[5] = {
+       UNIMPLEMENTED_PORT,     /* GPIO1 */
+       UNIMPLEMENTED_PORT,     /* GPIO2 */
+       UNIMPLEMENTED_PORT,     /* GPIO3 */
+       {w83627thf_port4_mux, 0x09, 1, 0xF4},
+       UNIMPLEMENTED_PORT,     /* GPIO5 */
+};
+
+static const struct winbond_chip winbond_chips[] = {
+       {WINBOND_W83627HF_ID,  ARRAY_SIZE(w83627hf),  w83627hf },
+       {WINBOND_W83627EHF_ID, ARRAY_SIZE(w83627ehf), w83627ehf},
+       {WINBOND_W83627THF_ID, ARRAY_SIZE(w83627thf), w83627thf},
+};
+
+#define WINBOND_SUPERIO_PORT1  0x2e
+#define WINBOND_SUPERIO_PORT2  0x4e
+
+/* We don't really care about the hardware monitor, but it offers better (more specific) device ID info than
+ * the simple device ID in the normal configuration registers.
+ * Note: This function expects to be called while the Super I/O is in config mode.
+ */
+static uint8_t w836xx_deviceid_hwmon(uint16_t sio_port)
+{
+       uint16_t hwmport;
+       uint16_t hwm_vendorid;
+       uint8_t hwm_deviceid;
+
+       sio_write(sio_port, 0x07, 0x0b); /* Select LDN 0xb (HWM). */
+       if ((sio_read(sio_port, 0x30) & (1 << 0)) != (1 << 0)) {
+               msg_pinfo("W836xx hardware monitor disabled or does not exist.\n");
+               return 0;
+       }
+       /* Get HWM base address (stored in LDN 0xb, index 0x60/0x61). */
+       hwmport = sio_read(sio_port, 0x60) << 8;
+       hwmport |= sio_read(sio_port, 0x61);
+       /* HWM address register = HWM base address + 5. */
+       hwmport += 5;
+       msg_pdbg2("W836xx Hardware Monitor at port %04x\n", hwmport);
+       /* FIXME: This busy check should happen before each HWM access. */
+       if (INB(hwmport) & 0x80) {
+               msg_pinfo("W836xx hardware monitor busy, ignoring it.\n");
+               return 0;
+       }
+       /* Set HBACS=1. */
+       sio_mask_alzheimer(hwmport, 0x4e, 0x80, 0x80);
+       /* Read upper byte of vendor ID. */
+       hwm_vendorid = sio_read(hwmport, 0x4f) << 8;
+       /* Set HBACS=0. */
+       sio_mask_alzheimer(hwmport, 0x4e, 0x00, 0x80);
+       /* Read lower byte of vendor ID. */
+       hwm_vendorid |= sio_read(hwmport, 0x4f);
+       if (hwm_vendorid != 0x5ca3) {
+               msg_pinfo("W836xx hardware monitor vendor ID weirdness: expected 0x5ca3, got %04x\n",
+                         hwm_vendorid);
+               return 0;
+       }
+       /* Set Bank=0. */
+       sio_mask_alzheimer(hwmport, 0x4e, 0x00, 0x07);
+       /* Read "chip" ID. We call this one the device ID. */
+       hwm_deviceid = sio_read(hwmport, 0x58);
+       return hwm_deviceid;
+}
+
+void probe_superio_winbond(void)
+{
+       struct superio s = {};
+       uint16_t winbond_ports[] = {WINBOND_SUPERIO_PORT1, WINBOND_SUPERIO_PORT2, 0};
+       uint16_t *i = winbond_ports;
+       uint8_t model;
+       uint8_t tmp;
+
+       s.vendor = SUPERIO_VENDOR_WINBOND;
+       for (; *i; i++) {
+               s.port = *i;
+               /* If we're already in Super I/O config more, the W836xx enter sequence won't hurt. */
+               w836xx_ext_enter(s.port);
+               model = sio_read(s.port, 0x20);
+               /* No response, no point leaving the config mode. */
+               if (model == 0xff)
+                       continue;
+               /* Try to leave config mode. If the ID register is still readable, it's not a Winbond chip. */
+               w836xx_ext_leave(s.port);
+               if (model == sio_read(s.port, 0x20)) {
+                       msg_pdbg("W836xx enter config mode worked or we were already in config mode. W836xx "
+                                "leave config mode had no effect.\n");
+                       if (model == 0x87) {
+                               /* ITE IT8707F and IT8710F are special: They need the W837xx enter sequence,
+                                * but they want the ITE exit sequence. Handle them here.
+                                */
+                               tmp = sio_read(s.port, 0x21);
+                               switch (tmp) {
+                               case 0x07:
+                               case 0x10:
+                                       s.vendor = SUPERIO_VENDOR_ITE;
+                                       s.model = (0x87 << 8) | tmp ;
+                                       msg_pdbg("Found ITE Super I/O, ID 0x%04hx on port "
+                                                "0x%x\n", s.model, s.port);
+                                       register_superio(s);
+                                       /* Exit ITE config mode. */
+                                       exit_conf_mode_ite(s.port);
+                                       /* Restore vendor for next loop iteration. */
+                                       s.vendor = SUPERIO_VENDOR_WINBOND;
+                                       continue;
+                               }
+                       }
+                       msg_pinfo("Active config mode, unknown reg 0x20 ID: %02x.\n", model);
+                       msg_pinfo("Please send the output of \"flashrom -V\" to \n"
+                                 "flashrom@flashrom.org with W836xx: your board name: flashrom -V\n"
+                                 "as the subject to help us finish support for your Super I/O. Thanks.\n");
+                       continue;
+               } 
+               /* The Super I/O reacts to W836xx enter and exit config mode, it's probably Winbond. */
+               w836xx_ext_enter(s.port);
+               s.model = sio_read(s.port, 0x20);
+               switch (s.model) {
+               case WINBOND_W83627HF_ID:
+               case WINBOND_W83627EHF_ID:
+               case WINBOND_W83627THF_ID:
+                       msg_pdbg("Found Winbond Super I/O, id %02hx\n", s.model);
+                       register_superio(s);
+                       break;
+               case WINBOND_W83697HF_ID:
+                       /* This code is extremely paranoid. */
+                       tmp = sio_read(s.port, 0x26) & 0x40;
+                       if (((tmp == 0x00) && (s.port != WINBOND_SUPERIO_PORT1)) ||
+                           ((tmp == 0x40) && (s.port != WINBOND_SUPERIO_PORT2))) {
+                               msg_pdbg("Winbond Super I/O probe weirdness: Port mismatch for ID "
+                                        "%02x at port %04x\n", s.model, s.port);
+                               break;
+                       }
+                       tmp = w836xx_deviceid_hwmon(s.port);
+                       /* FIXME: This might be too paranoid... */
+                       if (!tmp) {
+                               msg_pdbg("Probably not a Winbond Super I/O\n");
+                               break;
+                       }
+                       if (tmp != s.model) {
+                               msg_pinfo("W83 series hardware monitor device ID weirdness: expected %02x, "
+                                         "got %02x\n", WINBOND_W83697HF_ID, tmp);
+                               break;
+                       }
+                       msg_pinfo("Found Winbond Super I/O, id %02hx\n", s.model);
+                       register_superio(s);
+                       break;
+               }
+               w836xx_ext_leave(s.port);
+       }
+       return;
+}
+
+static const struct winbond_chip *winbond_superio_chipdef(void)
+{
+       int i, j;
+
+       for (i = 0; i < superio_count; i++) {
+               if (superios[i].vendor != SUPERIO_VENDOR_WINBOND)
+                       continue;
+               for (j = 0; j < ARRAY_SIZE(winbond_chips); j++)
+                       if (winbond_chips[j].device_id == superios[i].model)
+                               return &winbond_chips[j];
+       }
+       return NULL;
+}
+
+/*
+ * The chipid parameter goes away as soon as we have Super I/O matching in the
+ * board enable table. The call to winbond_superio_detect() goes away as
+ * soon as we have generic Super I/O detection code.
+ */
+static int winbond_gpio_set(uint16_t base, enum winbond_id chipid,
+                            int pin, int raise)
+{
+       const struct winbond_chip *chip = NULL;
+       const struct winbond_port *gpio;
+       int port = pin / 10;
+       int bit = pin % 10;
+
+       chip = winbond_superio_chipdef();
+       if (!chip) {
+               msg_perr("\nERROR: No supported Winbond Super I/O found\n");
+               return -1;
+       }
+       if (chip->device_id != chipid) {
+               msg_perr("\nERROR: Found Winbond chip with ID 0x%x, "
+                        "expected %x\n", chip->device_id, chipid);
+               return -1;
+       }
+       if (bit >= 8 || port == 0 || port > chip->gpio_port_count) {
+               msg_perr("\nERROR: winbond_gpio_set: Invalid GPIO number %d\n",
+                        pin);
+               return -1;
+       }
+
+       gpio = &chip->port[port - 1];
+
+       if (gpio->ldn == 0) {
+               msg_perr("\nERROR: GPIO%d is not supported yet on this"
+                         " winbond chip\n", port);
+               return -1;
+       }
+
+       w836xx_ext_enter(base);
+
+       /* Select logical device. */
+       sio_write(base, 0x07, gpio->ldn);
+
+       /* Activate logical device. */
+       sio_mask(base, 0x30, 1 << gpio->enable_bit, 1 << gpio->enable_bit);
+
+       /* Select GPIO function of that pin. */
+       if (gpio->mux && gpio->mux[bit].reg)
+               sio_mask(base, gpio->mux[bit].reg,
+                        gpio->mux[bit].data, gpio->mux[bit].mask);
+
+       sio_mask(base, gpio->base + 0, 0, 1 << bit);    /* Make pin output */
+       sio_mask(base, gpio->base + 2, 0, 1 << bit);    /* Clear inversion */
+       sio_mask(base, gpio->base + 1, raise << bit, 1 << bit);
+
+       w836xx_ext_leave(base);
+
+       return 0;
+}
+
+/*
+ * Winbond W83627HF: Raise GPIO24.
+ *
+ * Suited for:
+ *  - Agami Aruma
+ *  - IWILL DK8-HTX
+ */
+static int w83627hf_gpio24_raise_2e(void)
+{
+       return winbond_gpio_set(0x2e, WINBOND_W83627HF_ID, 24, 1);
+}
+
+/*
+ * Winbond W83627HF: Raise GPIO25.
+ *
+ * Suited for:
+ *  - MSI MS-6577
+ */
+static int w83627hf_gpio25_raise_2e(void)
+{
+       return winbond_gpio_set(0x2e, WINBOND_W83627HF_ID, 25, 1);
+}
+
+/*
+ * Winbond W83627EHF: Raise GPIO22.
+ *
+ * Suited for:
+ *  - ASUS A8N-VM CSM: AMD Socket 939 + GeForce 6150 (C51) + MCP51
+ */
+static int w83627ehf_gpio22_raise_2e(void)
+{
+       return winbond_gpio_set(0x2e, WINBOND_W83627EHF_ID, 22, 1);
+}
+
+/*
+ * Winbond W83627THF: Raise GPIO 44.
+ *
+ * Suited for:
+ *  - MSI K8T Neo2-F
+ */
+static int w83627thf_gpio44_raise_2e(void)
+{
+       return winbond_gpio_set(0x2e, WINBOND_W83627THF_ID, 44, 1);
+}
+
+/*
+ * Winbond W83627THF: Raise GPIO 44.
+ *
+ * Suited for:
+ *  - MSI K8N Neo3
+ */
+static int w83627thf_gpio44_raise_4e(void)
+{
+       return winbond_gpio_set(0x4e, WINBOND_W83627THF_ID, 44, 1);
+}
+
+/*
+ * Enable MEMW# and set ROM size to max.
+ * Supported chips: W83L517D, W83697HF/F/HG, W83697SF/UF/UG
+ */
+static void w836xx_memw_enable(uint16_t port)
+{
+       w836xx_ext_enter(port);
+       if (!(sio_read(port, 0x24) & 0x02)) {   /* Flash ROM enabled? */
+               /* Enable MEMW# and set ROM size select to max. (4M). */
+               sio_mask(port, 0x24, 0x28, 0x28);
+       }
+       w836xx_ext_leave(port);
+}
+
+/**
+ * Enable MEMW# and set ROM size to max.
+ * Supported chips:
+ * W83697HF/F/HG, W83697SF/UF/UG
+ */
+void w83697xx_memw_enable(uint16_t port)
+{
+       w836xx_ext_enter(port);
+       if (!(sio_read(port, 0x24) & 0x02)) { /* Flash ROM enabled? */
+               if((sio_read(port, 0x2A) & 0xF0) == 0xF0) {
+
+               /* CR24 Bits 7 & 2 must be set to 0 enable the flash ROM    */
+               /* address segments 000E0000h ~ 000FFFFFh on W83697SF/UF/UG */
+               /* These bits are reserved on W83697HF/F/HG                 */
+               /* Shouldn't be needed though.                              */
+
+               /* CR28 Bit3 must be set to 1 to enable flash access to     */
+               /* FFE80000h ~ FFEFFFFFh on W83697SF/UF/UG.                 */
+               /* This bit is reserved on W83697HF/F/HG which default to 0 */
+                       sio_mask(port, 0x28, 0x08, 0x08);
+
+                       /* Enable MEMW# and set ROM size select to max. (4M)*/
+                       sio_mask(port, 0x24, 0x28, 0x38);
+
+               } else {
+                       msg_perr("WARNING: Flash interface in use by GPIO!\n");
+               }
+       } else {
+               msg_pinfo("BIOS ROM is disabled\n");
+       }
+       w836xx_ext_leave(port);
+}
+
+/*
+ * 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
+ *  - MSI KM4M-V and KM4AM-V: VIA KM400/KM400A + VT8237
+ *  - MSI MS-6561 (745 Ultra): SiS 745 + W83697HF
+ *  - MSI MS-6787 (P4MAM-V/P4MAM-L): VIA P4M266 + VT8235
+ *  - ASRock K7S41: SiS 741 + SiS 963 + W83697HF
+ *  - ASRock K7S41GX: SiS 741GX + SiS 963L + W83697HF
+ */
+static int w836xx_memw_enable_2e(void)
+{
+       w836xx_memw_enable(0x2E);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - Termtek TK-3370 (rev. 2.5b)
+ */
+static int w836xx_memw_enable_4e(void)
+{
+       w836xx_memw_enable(0x4E);
+
+       return 0;
+}
+
+/*
+ * Suited for all boards with ITE IT8705F.
+ * The SIS950 Super I/O probably requires a similar flash write enable.
+ */
+int it8705f_write_enable(uint8_t port)
+{
+       uint8_t tmp;
+       int ret = 0;
+
+       enter_conf_mode_ite(port);
+       tmp = sio_read(port, 0x24);
+       /* Check if at least one flash segment is enabled. */
+       if (tmp & 0xf0) {
+               /* The IT8705F will respond to LPC cycles and translate them. */
+               internal_buses_supported = BUS_PARALLEL;
+               /* Flash ROM I/F Writes Enable */
+               tmp |= 0x04;
+               msg_pdbg("Enabling IT8705F flash ROM interface write.\n");
+               if (tmp & 0x02) {
+                       /* The data sheet contradicts itself about max size. */
+                       max_rom_decode.parallel = 1024 * 1024;
+                       msg_pinfo("IT8705F with very unusual settings. Please "
+                                 "send the output of \"flashrom -V\" to \n"
+                                 "flashrom@flashrom.org with "
+                                 "IT8705: your board name: flashrom -V\n"
+                                 "as the subject to help us finish "
+                                 "support for your Super I/O. Thanks.\n");
+                       ret = 1;
+               } else if (tmp & 0x08) {
+                       max_rom_decode.parallel = 512 * 1024;
+               } else {
+                       max_rom_decode.parallel = 256 * 1024;
+               }
+               /* Safety checks. The data sheet is unclear here: Segments 1+3
+                * overlap, no segment seems to cover top - 1MB to top - 512kB.
+                * We assume that certain combinations make no sense.
+                */
+               if (((tmp & 0x02) && !(tmp & 0x08)) || /* 1 MB en, 512 kB dis */
+                   (!(tmp & 0x10)) || /* 128 kB dis */
+                   (!(tmp & 0x40))) { /*  256/512 kB dis */
+                       msg_perr("Inconsistent IT8705F decode size!\n");
+                       ret = 1;
+               }
+               if (sio_read(port, 0x25) != 0) {
+                       msg_perr("IT8705F flash data pins disabled!\n");
+                       ret = 1;
+               }
+               if (sio_read(port, 0x26) != 0) {
+                       msg_perr("IT8705F flash address pins 0-7 disabled!\n");
+                       ret = 1;
+               }
+               if (sio_read(port, 0x27) != 0) {
+                       msg_perr("IT8705F flash address pins 8-15 disabled!\n");
+                       ret = 1;
+               }
+               if ((sio_read(port, 0x29) & 0x10) != 0) {
+                       msg_perr("IT8705F flash write enable pin disabled!\n");
+                       ret = 1;
+               }
+               if ((sio_read(port, 0x29) & 0x08) != 0) {
+                       msg_perr("IT8705F flash chip select pin disabled!\n");
+                       ret = 1;
+               }
+               if ((sio_read(port, 0x29) & 0x04) != 0) {
+                       msg_perr("IT8705F flash read strobe pin disabled!\n");
+                       ret = 1;
+               }
+               if ((sio_read(port, 0x29) & 0x03) != 0) {
+                       msg_perr("IT8705F flash address pins 16-17 disabled!\n");
+                       /* Not really an error if you use flash chips smaller
+                        * than 256 kByte, but such a configuration is unlikely.
+                        */
+                       ret = 1;
+               }
+               msg_pdbg("Maximum IT8705F parallel flash decode size is %u.\n",
+                       max_rom_decode.parallel);
+               if (ret) {
+                       msg_pinfo("Not enabling IT8705F flash write.\n");
+               } else {
+                       sio_write(port, 0x24, tmp);
+               }
+       } else {
+               msg_pdbg("No IT8705F flash segment enabled.\n");
+               ret = 0;
+       }
+       exit_conf_mode_ite(port);
+
+       return ret;
+}
+
+/*
+ * The ITE IT8707F is a custom chip made by ITE exclusively for ASUS.
+ * It uses the Winbond command sequence to enter extended configuration
+ * mode and the ITE sequence to exit.
+ *
+ * Registers seems similar to the ones on ITE IT8710F.
+ */
+static int it8707f_write_enable(uint8_t port)
+{
+       uint8_t tmp;
+
+       w836xx_ext_enter(port);
+
+       /* Set bit 3 (GLB_REG_WE) of reg 0x23: Makes reg 0x24-0x2A rw */
+       tmp = sio_read(port, 0x23);
+       tmp |= (1 << 3);
+       sio_write(port, 0x23, tmp);
+
+       /* Set bit 2 (FLASH_WE) and bit 3 (FLASH_IF_EN) of reg 0x24 */
+       tmp = sio_read(port, 0x24);
+       tmp |= (1 << 2) | (1 << 3);
+       sio_write(port, 0x24, tmp);
+
+       /* Clear bit 3 (GLB_REG_WE) of reg 0x23: Makes reg 0x24-0x2A ro */
+       tmp = sio_read(port, 0x23);
+       tmp &= ~(1 << 3);
+       sio_write(port, 0x23, tmp);
+
+       exit_conf_mode_ite(port);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - ASUS P4SC-E: SiS 651 + 962 + ITE IT8707F
+ */
+static int it8707f_write_enable_2e(void)
+{
+       return it8707f_write_enable(0x2e);
+}
+
+#define PC87360_ID 0xE1
+#define PC87364_ID 0xE4
+
+static int pc8736x_gpio_set(uint8_t chipid, 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) {
+               msg_perr("PC8736x: Invalid GPIO %d\n", gpio);
+               return -1;
+       }
+
+       id = sio_read(0x2E, 0x20);
+       if (id != chipid) {
+               msg_perr("PC8736x: unexpected ID %02x (expected %02x)\n",
+                        id, chipid);
+               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) {
+               msg_perr("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;
+}
+
+/*
+ * VIA VT823x: Set one of the GPIO pins.
+ */
+static int via_vt823x_gpio_set(uint8_t gpio, int raise)
+{
+       struct pci_dev *dev;
+       uint16_t base;
+       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:
+               msg_perr("\nERROR: VT823x ISA bridge not found.\n");
+               return -1;
+       }
+
+       if ((gpio >= 12) && (gpio <= 15)) {
+               /* GPIO12-15 -> output */
+               val = pci_read_byte(dev, 0xE4);
+               val |= 0x10;
+               pci_write_byte(dev, 0xE4, val);
+       } else if (gpio == 9) {
+               /* GPIO9 -> Output */
+               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 {
+               msg_perr("\nERROR: "
+                       "VT823x GPIO%02d is not implemented.\n", gpio);
+               return -1;
+       }
+
+       /* We need the I/O Base Address for this board's flash enable. */
+       base = pci_read_word(dev, 0x88) & 0xff80;
+
+       offset = 0x4C + gpio / 8;
+       bit = 0x01 << (gpio % 8);
+
+       val = INB(base + offset);
+       if (raise)
+               val |= bit;
+       else
+               val &= ~bit;
+       OUTB(val, base + offset);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - ASUS M2V-MX: VIA K8M890 + VT8237A + IT8716F
+ */
+static int via_vt823x_gpio5_raise(void)
+{
+       /* On M2V-MX: GPO5 is connected to WP# and TBL#. */
+       return via_vt823x_gpio_set(5, 1);
+}
+
+/*
+ * Suited for:
+ *  - VIA EPIA EK & N & NL
+ */
+static int via_vt823x_gpio9_raise(void)
+{
+       return via_vt823x_gpio_set(9, 1);
+}
+
+/*
+ * 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 via_vt823x_gpio15_raise(void)
+{
+       return via_vt823x_gpio_set(15, 1);
+}
+
+/*
+ * 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_msi_kt4v(void)
+{
+       int ret;
+
+       ret = via_vt823x_gpio_set(12, 1);
+       w836xx_memw_enable(0x2E);
+
+       return ret;
+}
+
+/*
+ * Suited for:
+ *  - ASUS P5A
+ *
+ * This is rather nasty code, but there's no way to do this cleanly.
+ * We're basically talking to some unknown device on SMBus, my guess
+ * is that it is the Winbond W83781D that lives near the DIP BIOS.
+ */
+static int board_asus_p5a(void)
+{
+       uint8_t tmp;
+       int i;
+
+#define ASUSP5A_LOOP 5000
+
+       OUTB(0x00, 0xE807);
+       OUTB(0xEF, 0xE803);
+
+       OUTB(0xFF, 0xE800);
+
+       for (i = 0; i < ASUSP5A_LOOP; i++) {
+               OUTB(0xE1, 0xFF);
+               if (INB(0xE800) & 0x04)
+                       break;
+       }
+
+       if (i == ASUSP5A_LOOP) {
+               msg_perr("Unable to contact device.\n");
+               return -1;
+       }
+
+       OUTB(0x20, 0xE801);
+       OUTB(0x20, 0xE1);
+
+       OUTB(0xFF, 0xE802);
+
+       for (i = 0; i < ASUSP5A_LOOP; i++) {
+               tmp = INB(0xE800);
+               if (tmp & 0x70)
+                       break;
+       }
+
+       if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
+               msg_perr("Failed to read device.\n");
+               return -1;
+       }
+
+       tmp = INB(0xE804);
+       tmp &= ~0x02;
+
+       OUTB(0x00, 0xE807);
+       OUTB(0xEE, 0xE803);
+
+       OUTB(tmp, 0xE804);
+
+       OUTB(0xFF, 0xE800);
+       OUTB(0xE1, 0xFF);
+
+       OUTB(0x20, 0xE801);
+       OUTB(0x20, 0xE1);
+
+       OUTB(0xFF, 0xE802);
+
+       for (i = 0; i < ASUSP5A_LOOP; i++) {
+               tmp = INB(0xE800);
+               if (tmp & 0x70)
+                       break;
+       }
+
+       if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
+               msg_perr("Failed to write to device.\n");
+               return -1;
+       }
+
+       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(void)
+{
+       /* 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;
+}
+
+/*
+ * 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_dl165_g6_enable(void)
+{
+       /* Variant of DL145, with slightly different pin placement. */
+       sio_mask(0xcd6, 0x44, 0x80, 0x80); /* TBL# */
+       sio_mask(0xcd6, 0x46, 0x04, 0x04); /* WP# */
+
+       return 0;
+}
+
+static int board_ibm_x3455(void)
+{
+       /* Raise GPIO13. */
+       sio_mask(0xcd6, 0x45, 0x20, 0x20);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - Shuttle FN25 (SN25P): AMD S939 + NVIDIA CK804 (nForce4)
+ */
+static int board_shuttle_fn25(void)
+{
+       struct pci_dev *dev;
+
+       dev = pci_dev_find(0x10DE, 0x0050);     /* NVIDIA CK804 ISA bridge. */
+       if (!dev) {
+               msg_perr("\nERROR: NVIDIA nForce4 ISA bridge not found.\n");
+               return -1;
+       }
+
+       /* One of those bits seems to be connected to TBL#, but -ENOINFO. */
+       pci_write_byte(dev, 0x92, 0);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ * - Elitegroup GeForce6100SM-M: NVIDIA MCP61 + ITE IT8726F
+ */
+static int board_ecs_geforce6100sm_m(void)
+{
+       struct pci_dev *dev;
+       uint32_t tmp;
+
+       dev = pci_dev_find(0x10DE, 0x03EB);     /* NVIDIA MCP61 SMBus. */
+       if (!dev) {
+               msg_perr("\nERROR: NVIDIA MCP61 SMBus not found.\n");
+               return -1;
+       }
+
+       tmp = pci_read_byte(dev, 0xE0);
+       tmp &= ~(1 << 3);
+       pci_write_byte(dev, 0xE0, tmp);
+
+       return 0;
+}
+
+/*
+ * Very similar to AMD 8111 IO Hub.
+ */
+static int nvidia_mcp_gpio_set(int gpio, int raise)
+{
+       struct pci_dev *dev;
+       uint16_t base, devclass;
+       uint8_t tmp;
+
+       if ((gpio < 0) || (gpio >= 0x40)) {
+               msg_perr("\nERROR: unsupported GPIO: %d.\n", gpio);
+               return -1;
+       }
+
+       /* Check for the ISA bridge first. */
+       dev = pci_dev_find_vendorclass(0x10DE, 0x0601);
+       switch (dev->device_id) {
+       case 0x0030: /* CK804 */
+       case 0x0050: /* MCP04 */
+       case 0x0060: /* MCP2 */
+       case 0x00E0: /* CK8 */
+               break;
+       case 0x0260: /* MCP51 */
+       case 0x0261: /* MCP51 */
+       case 0x0360: /* MCP55 */
+       case 0x0364: /* MCP55 */
+               /* find SMBus controller on *this* southbridge */
+               /* The infamous Tyan S2915-E has two south bridges; they are
+                  easily told apart from each other by the class of the 
+                  LPC bridge, but have the same SMBus bridge IDs */
+               if (dev->func != 0) {
+                       msg_perr("MCP LPC bridge at unexpected function"
+                                " number %d\n", dev->func);
+                       return -1;
+               }
+
+#if PCI_LIB_VERSION >= 0x020200
+               dev = pci_get_dev(pacc, dev->domain, dev->bus, dev->dev, 1);
+#else
+               /* pciutils/libpci before version 2.2 is too old to support
+                * PCI domains. Such old machines usually don't have domains
+                * besides domain 0, so this is not a problem.
+                */
+               dev = pci_get_dev(pacc, dev->bus, dev->dev, 1);
+#endif
+               if (!dev) {
+                       msg_perr("MCP SMBus controller could not be found\n");
+                       return -1;
+               }
+               devclass = pci_read_word(dev, PCI_CLASS_DEVICE);
+               if (devclass != 0x0C05) {
+                       msg_perr("Unexpected device class %04x for SMBus"
+                                " controller\n", devclass);
+                       return -1;
+               }
+               break;
+       default:
+               msg_perr("\nERROR: no NVIDIA LPC/SMBus controller found.\n");
+               return -1;
+       }
+
+       base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */
+       base += 0xC0;
+
+       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:
+ *  - ASUS A8M2N-LA (HP OEM "NodusM3-GL8E"): NVIDIA MCP51
+ *  - ASUS A8N-LA (HP OEM "Nagami-GL8E"): NVIDIA MCP51
+ *  - ASUS M2NBP-VM CSM: NVIDIA MCP51
+ */
+static int nvidia_mcp_gpio0_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x00, 1);
+}
+
+/*
+ * Suited for:
+ *  - abit KN8 Ultra: NVIDIA CK804
+ */
+static int nvidia_mcp_gpio2_lower(void)
+{
+       return nvidia_mcp_gpio_set(0x02, 0);
+}
+
+/*
+ * Suited for:
+ *  - Foxconn 6150K8MD-8EKRSH: Socket 939 + NVIDIA MCP51
+ *  - MSI K8N Neo4: NVIDIA CK804. TODO: Should probably be K8N Neo4 Platinum, see http://www.coreboot.org/pipermail/flashrom/2010-August/004362.html.
+ *  - MSI K8NGM2-L: NVIDIA MCP51
+ *  - MSI K9N SLI: NVIDIA MCP55
+ */
+static int nvidia_mcp_gpio2_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x02, 1);
+}
+
+/*
+ * Suited for:
+ *  - EPoX EP-8NPA7I: Socket 754 + NVIDIA nForce4 4X
+ */
+static int nvidia_mcp_gpio4_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x04, 1);
+}
+
+/*
+ * Suited for:
+ *  - HP xw9400 (Tyan S2915-E OEM): Dual(!) NVIDIA MCP55
+ *
+ * Notes: a) There are two MCP55 chips, so also two SMBus bridges on that
+ *           board. We can't tell the SMBus logical devices apart, but we
+ *           can tell the LPC bridge functions apart.
+ *           We need to choose the SMBus bridge next to the LPC bridge with
+ *           ID 0x364 and the "LPC bridge" class.
+ *        b) #TBL is hardwired on that board to a pull-down. It can be
+ *           overridden by connecting the two solder points next to F2.
+ */
+static int nvidia_mcp_gpio5_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x05, 1);
+}
+
+/*
+ * Suited for:
+ *  - abit NF7-S: NVIDIA CK804
+ */
+static int nvidia_mcp_gpio8_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x08, 1);
+}
+
+/*
+ * Suited for:
+ *  - GIGABYTE GA-K8NS Pro-939: Socket 939 + NVIDIA nForce3  + CK8
+ */
+static int nvidia_mcp_gpio0a_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x0a, 1);
+}
+
+/*
+ * Suited for:
+ *  - MSI K8N Neo2 Platinum: Socket 939 + nForce3 Ultra + CK8
+ */
+static int nvidia_mcp_gpio0c_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x0c, 1);
+}
+
+/*
+ * Suited for:
+ *  - abit NF-M2 nView: Socket AM2 + NVIDIA MCP51
+ */
+static int nvidia_mcp_gpio4_lower(void)
+{
+       return nvidia_mcp_gpio_set(0x04, 0);
+}
+
+/*
+ * Suited for:
+ *  - ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04
+ */
+static int nvidia_mcp_gpio10_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x10, 1);
+}
+
+/*
+ * Suited for:
+ *  - GIGABYTE GA-K8N-SLI: AMD socket 939 + NVIDIA CK804 + ITE IT8712F
+ */
+static int nvidia_mcp_gpio21_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x21, 0x01);
+}
+
+/*
+ * Suited for:
+ *  - EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2
+ */
+static int nvidia_mcp_gpio31_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x31, 0x01);
+}
+
+/*
+ * Suited for:
+ *  - GIGABYTE GA-K8N51GMF: Socket 754 + Geforce 6100 + MCP51
+ *  - GIGABYTE GA-K8N51GMF-9: Socket 939 + Geforce 6100 + MCP51
+ */
+static int nvidia_mcp_gpio3b_raise(void)
+{
+       return nvidia_mcp_gpio_set(0x3b, 1);
+}
+
+/*
+ * Suited for:
+ *  - Sun Ultra 40 M2: Dual Socket F (1207) + MCP55
+ */
+static int board_sun_ultra_40_m2(void)
+{
+       int ret;
+       uint8_t reg;
+       uint16_t base;
+       struct pci_dev *dev;
+
+       ret = nvidia_mcp_gpio4_lower();
+       if (ret)
+               return ret;
+
+       dev = pci_dev_find(0x10de, 0x0364); /* NVIDIA MCP55 LPC bridge */
+       if (!dev) {
+               msg_perr("\nERROR: NVIDIA MCP55 LPC bridge not found.\n");
+               return -1;
+       }
+
+       base = pci_read_word(dev, 0xb4); /* some IO BAR? */
+       if (!base)
+               return -1;
+
+       reg = INB(base + 0x4b);
+       reg |= 0x10;
+       OUTB(reg, base + 0x4b);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - Artec Group DBE61 and DBE62
+ */
+static int board_artecgroup_dbe6x(void)
+{
+#define DBE6x_MSR_DIVIL_BALL_OPTS      0x51400015
+#define DBE6x_PRI_BOOT_LOC_SHIFT       2
+#define DBE6x_BOOT_OP_LATCHED_SHIFT    8
+#define DBE6x_SEC_BOOT_LOC_SHIFT       10
+#define DBE6x_PRI_BOOT_LOC             (3 << DBE6x_PRI_BOOT_LOC_SHIFT)
+#define DBE6x_BOOT_OP_LATCHED          (3 << DBE6x_BOOT_OP_LATCHED_SHIFT)
+#define DBE6x_SEC_BOOT_LOC             (3 << DBE6x_SEC_BOOT_LOC_SHIFT)
+#define DBE6x_BOOT_LOC_FLASH           2
+#define DBE6x_BOOT_LOC_FWHUB           3
+
+       msr_t msr;
+       unsigned long boot_loc;
+
+       /* Geode only has a single core */
+       if (setup_cpu_msr(0))
+               return -1;
+
+       msr = rdmsr(DBE6x_MSR_DIVIL_BALL_OPTS);
+
+       if ((msr.lo & (DBE6x_BOOT_OP_LATCHED)) ==
+           (DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT))
+               boot_loc = DBE6x_BOOT_LOC_FWHUB;
+       else
+               boot_loc = DBE6x_BOOT_LOC_FLASH;
+
+       msr.lo &= ~(DBE6x_PRI_BOOT_LOC | DBE6x_SEC_BOOT_LOC);
+       msr.lo |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) |
+                  (boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT));
+
+       wrmsr(DBE6x_MSR_DIVIL_BALL_OPTS, msr);
+
+       cleanup_cpu_msr();
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - ASUS A8AE-LE (Codename AmberineM; used in Compaq Presario 061)
+ * Datasheet(s) used:
+ *  - AMD document 43009 "AMD SB700/710/750 Register Reference Guide" rev. 1.00
+ */
+static int amd_sbxxx_gpio9_raise(void)
+{
+       struct pci_dev *dev;
+       uint32_t reg;
+
+       dev = pci_dev_find(0x1002, 0x4372); /* AMD SMBus controller */
+       if (!dev) {
+               msg_perr("\nERROR: AMD SMBus Controller (0x4372) not found.\n");
+               return -1;
+       }
+
+       reg = pci_read_long(dev, 0xA8); /* GPIO_12_to_4_Cntrl CI_Reg: A8h-ABh */
+       /* enable output (0: enable, 1: tristate):
+          GPIO9 output enable is at bit 5 in 0xA9 */
+       reg &= ~((uint32_t)1<<(8+5));
+       /* raise:
+          GPIO9 output register is at bit 5 in 0xA8 */
+       reg |= (1<<5);
+       pci_write_long(dev, 0xA8, reg);
+
+       return 0;
+}
+
+/*
+ * Helper function to raise/drop a given gpo line on Intel PIIX4{,E,M}.
+ */
+static int intel_piix4_gpo_set(unsigned int gpo, int raise)
+{
+       unsigned int gpo_byte, gpo_bit;
+       struct pci_dev *dev;
+       uint32_t tmp, base;
+
+       /* GPO{0,8,27,28,30} are always available. */
+       static const uint32_t nonmuxed_gpos = 0x58000101;
+
+       static const struct {unsigned int reg, mask, value; } piix4_gpo[] = {
+               {0},
+               {0xB0, 0x0001, 0x0000},        /* GPO1... */
+               {0xB0, 0x0001, 0x0000},
+               {0xB0, 0x0001, 0x0000},
+               {0xB0, 0x0001, 0x0000},
+               {0xB0, 0x0001, 0x0000},
+               {0xB0, 0x0001, 0x0000},
+               {0xB0, 0x0001, 0x0000},        /* ...GPO7: GENCFG bit 0 */
+               {0},
+               {0xB0, 0x0100, 0x0000},        /* GPO9:  GENCFG bit 8 */
+               {0xB0, 0x0200, 0x0000},        /* GPO10: GENCFG bit 9 */
+               {0xB0, 0x0400, 0x0000},        /* GPO11: GENCFG bit 10 */
+               {0x4E, 0x0100, 0x0000},        /* GPO12... */
+               {0x4E, 0x0100, 0x0000},
+               {0x4E, 0x0100, 0x0000},        /* ...GPO14: XBCS bit 8 */
+               {0xB2, 0x0002, 0x0002},        /* GPO15... */
+               {0xB2, 0x0002, 0x0002},        /* ...GPO16: GENCFG bit 17 */
+               {0xB2, 0x0004, 0x0004},        /* GPO17: GENCFG bit 18 */
+               {0xB2, 0x0008, 0x0008},        /* GPO18: GENCFG bit 19 */
+               {0xB2, 0x0010, 0x0010},        /* GPO19: GENCFG bit 20 */
+               {0xB2, 0x0020, 0x0020},        /* GPO20: GENCFG bit 21 */
+               {0xB2, 0x0040, 0x0040},        /* GPO21: GENCFG bit 22 */
+               {0xB2, 0x1000, 0x1000},        /* GPO22... */
+               {0xB2, 0x1000, 0x1000},        /* ...GPO23: GENCFG bit 28 */
+               {0xB2, 0x2000, 0x2000},        /* GPO24: GENCFG bit 29 */
+               {0xB2, 0x4000, 0x4000},        /* GPO25: GENCFG bit 30 */
+               {0xB2, 0x8000, 0x8000},        /* GPO26: GENCFG bit 31 */
+               {0},
+               {0},
+               {0x4E, 0x0100, 0x0000},        /* ...GPO29: XBCS bit 8 */
+               {0}
+       };
+
+       dev = pci_dev_find(0x8086, 0x7110);     /* Intel PIIX4 ISA bridge */
+       if (!dev) {
+               msg_perr("\nERROR: Intel PIIX4 ISA bridge not found.\n");
+               return -1;
+       }
+
+       /* Sanity check. */
+       if (gpo > 30) {
+               msg_perr("\nERROR: Intel PIIX4 has no GPO%d.\n", gpo);
+               return -1;
+       }
+
+       if ((((1 << gpo) & nonmuxed_gpos) == 0) &&
+           ((pci_read_word(dev, piix4_gpo[gpo].reg) & piix4_gpo[gpo].mask) !=
+            piix4_gpo[gpo].value)) {
+               msg_perr("\nERROR: PIIX4 GPO%d not programmed for output.\n", gpo);
+               return -1;
+       }
+
+       dev = pci_dev_find(0x8086, 0x7113);     /* Intel PIIX4 PM */
+       if (!dev) {
+               msg_perr("\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 OPLX-M
+ *  - ASUS P2B-N
+ */
+static int intel_piix4_gpo18_lower(void)
+{
+       return intel_piix4_gpo_set(18, 0);
+}
+
+/*
+ * Suited for:
+ *  - MSI MS-6163 v2 (MS-6163 Pro): Intel 440BX + PIIX4E + Winbond W83977EF
+ */
+static int intel_piix4_gpo14_raise(void)
+{
+       return intel_piix4_gpo_set(14, 1);
+}
+
+/*
+ * Suited for:
+ *  - EPoX EP-BX3
+ */
+static int intel_piix4_gpo22_raise(void)
+{
+       return intel_piix4_gpo_set(22, 1);
+}
+
+/*
+ * Suited for:
+ *  - abit BM6
+ */
+static int intel_piix4_gpo26_lower(void)
+{
+       return intel_piix4_gpo_set(26, 0);
+}
+
+/*
+ * Suited for:
+ *  - Intel SE440BX-2
+ */
+static int intel_piix4_gpo27_lower(void)
+{
+       return intel_piix4_gpo_set(27, 0);
+}
+
+/*
+ * Suited for:
+ *  - Dell OptiPlex GX1
+ */
+static int intel_piix4_gpo30_lower(void)
+{
+       return intel_piix4_gpo_set(30, 0);
+}
+
+/*
+ * Set a GPIO line on a given Intel ICH LPC controller.
+ */
+static int intel_ich_gpio_set(int gpio, int raise)
+{
+       /* 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 */
+       };
+
+       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) {
+               uint16_t device_class;
+               /* libpci before version 2.2.4 does not store class info. */
+               device_class = pci_read_word(dev, PCI_CLASS_DEVICE);
+               if ((dev->vendor_id == 0x8086) &&
+                   (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;
+               }
+       }
+
+       if (!dev) {
+               msg_perr("\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) {
+               msg_perr("\nERROR: This Intel LPC bridge does not allow"
+                        " setting GPIO%02d\n", gpio);
+               return -1;
+       }
+
+       msg_pdbg("\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))) {
+                               msg_perr("\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))) {
+                               msg_perr("\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);
+
+               /* 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))) {
+                       msg_perr("\nERROR: This Intel LPC bridge does "
+                               "not allow setting GPIO%02d\n", gpio + 64);
+                       return -1;
+               }
+
+               /* Set GPIO to OUTPUT. */
+               tmp = INL(base + 0x44);
+               tmp &= ~(1 << gpio);
+               OUTL(tmp, base + 0x44);
+
+               /* Raise GPIO line. */
+               tmp = INL(base + 0x48);
+               if (raise)
+                       tmp |= 1 << gpio;
+               else
+                       tmp &= ~(1 << gpio);
+               OUTL(tmp, base + 0x48);
+       }
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - abit IP35: Intel P35 + ICH9R
+ *  - abit IP35 Pro: Intel P35 + ICH9R
+ *  - ASUS P5LD2
+ */
+static int intel_ich_gpio16_raise(void)
+{
+       return intel_ich_gpio_set(16, 1);
+}
+
+/*
+ * Suited for:
+ *  - HP Puffer2-UL8E (ASUS PTGD-LA OEM): LGA775 + 915 + ICH6
+ */
+static int intel_ich_gpio18_raise(void)
+{
+       return intel_ich_gpio_set(18, 1);
+}
+
+/*
+ * Suited for:
+ *  - MSI MS-7046: LGA775 + 915P + ICH6
+ */
+static int intel_ich_gpio19_raise(void)
+{
+       return intel_ich_gpio_set(19, 1);
+}
+
+/*
+ * Suited for:
+ *  - ASUS P5BV-R: LGA775 + 3200 + ICH7
+ */
+static int intel_ich_gpio20_raise(void)
+{
+       return intel_ich_gpio_set(20, 1);
+}
+
+/*
+ * Suited for:
+ *  - ASUS P4B266LM (Sony Vaio PCV-RX650): socket478 + 845D + ICH2
+ *  - ASUS P4C800-E Deluxe: socket478 + 875P + ICH5
+ *  - ASUS P4P800: Intel socket478 + 865PE + ICH5R
+ *  - ASUS P4P800-E Deluxe: Intel socket478 + 865PE + ICH5R
+ *  - ASUS P4P800-VM: Intel socket478 + 865PE + ICH5R
+ *  - ASUS P5GD1 Pro: Intel LGA 775 + 915P + ICH6R
+ *  - ASUS P5GD2 Premium: Intel LGA775 + 915G + ICH6R
+ *  - ASUS P5GDC Deluxe: Intel socket775 + 915P + ICH6R
+ *  - ASUS P5PE-VM: Intel LGA775 + 865G + ICH5
+ *  - ASUS TUSL2-C: Intel socket370 + 815 + ICH2
+ *  - Samsung Polaris 32: socket478 + 865P + ICH5
+ */
+static int intel_ich_gpio21_raise(void)
+{
+       return intel_ich_gpio_set(21, 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
+ *  - TriGem Anaheim-3: socket370 + Intel 810 + ICH
+ */
+static int intel_ich_gpio22_raise(void)
+{
+       return intel_ich_gpio_set(22, 1);
+}
+
+/*
+ * Suited for:
+ *  - ASUS A8Jm (laptop): Intel 945 + ICH7
+ *  - ASUS P5LP-LE used in ...
+ *    - HP Media Center m7270.fr Desktop PC as "Lithium-UL8E"
+ *    - Epson Endeavor MT7700
+ */
+static int intel_ich_gpio34_raise(void)
+{
+       return intel_ich_gpio_set(34, 1);
+}
+
+/*
+ * Suited for:
+ *  - AOpen i945GMx-VFX: Intel 945GM + ICH7-M used in ...
+ *    - FSC ESPRIMO Q5010 (SMBIOS: D2544-B1)
+ */
+static int intel_ich_gpio38_raise(void)
+{
+       return intel_ich_gpio_set(38, 1);
+}
+
+/*
+ * Suited for:
+ *  - ASUS M6Ne (laptop): socket 479M (guessed) + Intel 855PM + ICH4-M
+ */
+static int intel_ich_gpio43_raise(void)
+{
+       return intel_ich_gpio_set(43, 1);
+}
+
+/*
+ * Suited for:
+ *  - HP Vectra VL400: 815 + ICH + PC87360
+ */
+static int board_hp_vl400(void)
+{
+       int ret;
+       ret = intel_ich_gpio_set(25, 1);        /* Master write enable ? */
+       if (!ret)
+               ret = pc8736x_gpio_set(PC87360_ID, 0x09, 1);    /* #WP ? */
+       if (!ret)
+               ret = pc8736x_gpio_set(PC87360_ID, 0x27, 1);    /* #TBL */
+       return ret;
+}
+
+/*
+ * Suited for:
+ *  - HP e-Vectra P2706T: 810E + ICH + PC87364
+ */
+static int board_hp_p2706t(void)
+{
+       int ret;
+       ret = pc8736x_gpio_set(PC87364_ID, 0x25, 1);
+       if (!ret)
+               ret = pc8736x_gpio_set(PC87364_ID, 0x26, 1);
+       return ret;
+}
+
+/*
+ * Suited for:
+ *  - Dell PowerEdge 1850: Intel PPGA604 + E7520 + ICH5R
+ *  - ASRock P4i65GV: Intel Socket478 + 865GV + ICH5R
+ *  - ASRock 775i65G: Intel LGA 775 + 865G + ICH5
+ *  - MSI MS-6391 (845 Pro4): Intel Socket478 + 845 + ICH2
+ */
+static int intel_ich_gpio23_raise(void)
+{
+       return intel_ich_gpio_set(23, 1);
+}
+
+/*
+ * Suited for:
+ *  - GIGABYTE GA-6IEM: Intel Socket370 + i815 + ICH2
+ *  - GIGABYTE GA-8IRML: Intel Socket478 + i845 + ICH2
+ */
+static int intel_ich_gpio25_raise(void)
+{
+       return intel_ich_gpio_set(25, 1);
+}
+
+/*
+ * Suited for:
+ *  - IBASE MB899: i945GM + ICH7
+ */
+static int intel_ich_gpio26_raise(void)
+{
+       return intel_ich_gpio_set(26, 1);
+}
+
+/*
+ * Suited for:
+ *  - P4SD-LA (HP OEM): i865 + ICH5
+ *  - GIGABYTE GA-8IP775: 865P + ICH5
+ *  - GIGABYTE GA-8PE667 Ultra 2: socket 478 + i845PE + ICH4
+ *  - MSI MS-6788-40 (aka 848P Neo-V)
+ */
+static int intel_ich_gpio32_raise(void)
+{
+       return intel_ich_gpio_set(32, 1);
+}
+
+/*
+ * Suited for:
+ *  - AOpen i975Xa-YDG: i975X + ICH7 + W83627EHF
+ */
+static int board_aopen_i975xa_ydg(void)
+{
+       int ret;
+
+       /* Vendor BIOS ends up in LDN6... maybe the board enable is wrong,
+        * or perhaps it's not needed at all?
+        * The regs it tries to touch are 0xF0, 0xF1, 0xF2 which means if it
+        * were in the right LDN, it would have to be GPIO1 or GPIO3.
+        */
+/*
+       ret = winbond_gpio_set(0x2e, WINBOND_W83627EHF_ID, x, 0)
+       if (!ret)
+*/
+               ret = intel_ich_gpio_set(33, 1);
+
+       return ret;
+}
+
+/*
+ * Suited for:
+ *  - Acorp 6A815EPD: socket 370 + intel 815 + ICH2
+ */
+static int board_acorp_6a815epd(void)
+{
+       int ret;
+
+       /* 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 ret;
+}
+
+/*
+ * Suited for:
+ *  - Kontron 986LCD-M: Socket478 + 915GM + ICH7R
+ */
+static int board_kontron_986lcd_m(void)
+{
+       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 via_apollo_gpo_set(int gpio, int raise)
+{
+       struct pci_dev *dev;
+       uint32_t base, tmp;
+
+       /* VT82C686 power management */
+       dev = pci_dev_find(0x1106, 0x3057);
+       if (!dev) {
+               msg_perr("\nERROR: VT82C686 PM device not found.\n");
+               return -1;
+       }
+
+       msg_pdbg("\nVIA Apollo ACPI: %sing GPIO%02d.\n",
+                raise ? "Rais" : "Dropp", gpio);
+
+       /* Select GPO function on multiplexed pins. */
+       tmp = pci_read_byte(dev, 0x54);
+       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 = INL(base + 0x4C);
+       if (raise)
+               tmp |= 1U << gpio;
+       else
+               tmp &= ~(1U << gpio);
+       OUTL(tmp, base + 0x4C);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - abit VT6X4: Pro133x + VT82C686A
+ *  - abit VA6: Pro133x + VT82C686A
+ */
+static int via_apollo_gpo4_lower(void)
+{
+       return via_apollo_gpo_set(4, 0);
+}
+
+/*
+ * Suited for:
+ *  - Soyo SY-7VCA: Pro133A + VT82C686
+ */
+static int via_apollo_gpo0_lower(void)
+{
+       return via_apollo_gpo_set(0, 0);
+}
+
+/*
+ * Enable some GPIO pin on SiS southbridge and enables SIO flash writes.
+ *
+ * Suited for:
+ *  - MSI 651M-L: SiS651 / SiS962
+ *  - GIGABYTE GA-8SIMLH
+ */
+static int sis_gpio0_raise_and_w836xx_memw(void)
+{
+       struct pci_dev *dev;
+       uint16_t base, temp;
+
+       dev = pci_dev_find(0x1039, 0x0962);
+       if (!dev) {
+               msg_perr("Expected south bridge not found\n");
+               return 1;
+       }
+
+       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;
+}
+
+/*
+ * Find the runtime registers of an SMSC Super I/O, after verifying its
+ * chip ID.
+ *
+ * Returns the base port of the runtime register block, or 0 on error.
+ */
+static uint16_t smsc_find_runtime(uint16_t sio_port, uint16_t chip_id,
+                                  uint8_t logical_device)
+{
+       uint16_t rt_port = 0;
+
+       /* Verify the chip ID. */
+       OUTB(0x55, sio_port);  /* Enable configuration. */
+       if (sio_read(sio_port, 0x20) != chip_id) {
+               msg_perr("\nERROR: SMSC Super I/O not found.\n");
+               goto out;
+       }
+
+       /* If the runtime block is active, get its address. */
+       sio_write(sio_port, 0x07, logical_device);
+       if (sio_read(sio_port, 0x30) & 1) {
+               rt_port = (sio_read(sio_port, 0x60) << 8)
+                         | sio_read(sio_port, 0x61);
+       }
+
+       if (rt_port == 0) {
+               msg_perr("\nERROR: "
+                       "Super I/O runtime interface not available.\n");
+       }
+out:
+       OUTB(0xaa, sio_port);  /* Disable configuration. */
+       return rt_port;
+}
+
+/*
+ * Disable write protection on the Mitac 6513WU. WP# on the FWH is
+ * connected to GP30 on the Super I/O, and TBL# is always high.
+ */
+static int board_mitac_6513wu(void)
+{
+       struct pci_dev *dev;
+       uint16_t rt_port;
+       uint8_t val;
+
+       dev = pci_dev_find(0x8086, 0x2410);     /* Intel 82801AA ISA bridge */
+       if (!dev) {
+               msg_perr("\nERROR: Intel 82801AA ISA bridge not found.\n");
+               return -1;
+       }
+
+       rt_port = smsc_find_runtime(0x4e, 0x54 /* LPC47U33x */, 0xa);
+       if (rt_port == 0)
+               return -1;
+
+       /* Configure the GPIO pin. */
+       val = INB(rt_port + 0x33);  /* GP30 config */
+       val &= ~0x87;               /* Output, non-inverted, GPIO, push/pull */
+       OUTB(val, rt_port + 0x33);
+
+       /* Disable write protection. */
+       val = INB(rt_port + 0x4d);  /* GP3 values */
+       val |= 0x01;                /* Set GP30 high. */
+       OUTB(val, rt_port + 0x4d);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - abit AV8: Socket939 + K8T800Pro + VT8237
+ */
+static int board_abit_av8(void)
+{
+       uint8_t val;
+
+       /* Raise GPO pins GP22 & GP23 */
+       val = INB(0x404E);
+       val |= 0xC0;
+       OUTB(val, 0x404E);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ *  - ASUS A7V333: VIA KT333 + VT8233A + IT8703F
+ *  - ASUS A7V8X: VIA KT400 + VT8235 + IT8703F
+ */
+static int it8703f_gpio51_raise(void)
+{
+       uint16_t id, base;
+       uint8_t tmp;
+
+       /* Find the IT8703F. */
+       w836xx_ext_enter(0x2E);
+       id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21);
+       w836xx_ext_leave(0x2E);
+
+       if (id != 0x8701) {
+               msg_perr("\nERROR: IT8703F Super I/O not found.\n");
+               return -1;
+       }
+
+       /* Get the GP567 I/O base. */
+       w836xx_ext_enter(0x2E);
+       sio_write(0x2E, 0x07, 0x0C);
+       base = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61);
+       w836xx_ext_leave(0x2E);
+
+       if (!base) {
+               msg_perr("\nERROR: Failed to read IT8703F Super I/O GPIO"
+                       " Base.\n");
+               return -1;
+       }
+
+       /* Raise GP51. */
+       tmp = INB(base);
+       tmp |= 0x02;
+       OUTB(tmp, base);
+
+       return 0;
+}
+
+/*
+ * General routine for raising/dropping GPIO lines on the ITE IT87xx.
+ */
+static int it87_gpio_set(unsigned int gpio, int raise)
+{
+       int allowed, sio;
+       unsigned int port;
+       uint16_t base, sioport;
+       uint8_t tmp;
+
+       /* IT87 GPIO configuration table */
+       static const struct it87cfg {
+               uint16_t id;
+               uint8_t base_reg;
+               uint32_t bank0;
+               uint32_t bank1;
+               uint32_t bank2;
+       } it87_gpio_table[] = {
+               {0x8712, 0x62, 0xCFF3FC00, 0x00FCFF3F,          0},
+               {0x8718, 0x62, 0xCFF37C00, 0xF3FCDF3F, 0x0000000F},
+               {0, 0, 0, 0, 0} /* end marker */
+       };
+       const struct it87cfg *cfg = NULL;
+
+       /* Find the Super I/O in the probed list */
+       for (sio = 0; sio < superio_count; sio++) {
+               int i;
+               if (superios[sio].vendor != SUPERIO_VENDOR_ITE)
+                       continue;
+
+               /* Is this device in our list? */
+               for (i = 0; it87_gpio_table[i].id; i++)
+                       if (superios[sio].model == it87_gpio_table[i].id) {
+                               cfg = &it87_gpio_table[i];
+                               goto found;
+                       }
+       }
+
+       if (cfg == NULL) {
+               msg_perr("\nERROR: No IT87 Super I/O GPIO configuration "
+                        "found.\n");
+               return -1;
+       }
+
+found:
+       /* Check whether the gpio is allowed. */
+       if (gpio < 32)
+               allowed = (cfg->bank0 >> gpio) & 0x01;
+       else if (gpio < 64)
+               allowed = (cfg->bank1 >> (gpio - 32)) & 0x01;
+       else if (gpio < 96)
+               allowed = (cfg->bank2 >> (gpio - 64)) & 0x01;
+       else
+               allowed = 0;
+
+       if (!allowed) {
+               msg_perr("\nERROR: IT%02X does not allow setting GPIO%02u.\n",
+                        cfg->id, gpio);
+               return -1;
+       }
+
+       /* Read the Simple I/O Base Address Register */
+       sioport = superios[sio].port;
+       enter_conf_mode_ite(sioport);
+       sio_write(sioport, 0x07, 0x07);
+       base = (sio_read(sioport, cfg->base_reg) << 8) |
+               sio_read(sioport, cfg->base_reg + 1);
+       exit_conf_mode_ite(sioport);
+
+       if (!base) {
+               msg_perr("\nERROR: Failed to read IT87 Super I/O GPIO Base.\n");
+               return -1;
+       }
+
+       msg_pdbg("Using IT87 GPIO base 0x%04x\n", base);
+
+       port = gpio / 10 - 1;
+       gpio %= 10;
+
+       /* set GPIO. */
+       tmp = INB(base + port);
+       if (raise)
+               tmp |= 1 << gpio;
+       else
+               tmp &= ~(1 << gpio);
+       OUTB(tmp, base + port);
+
+       return 0;
+}
+
+/*
+ * Suited for:
+ * - ASUS A7N8X-VM/400: NVIDIA nForce2 IGP2 + IT8712F
+ */
+static int it8712f_gpio12_raise(void)
+{
+       return it87_gpio_set(12, 1);
+}
+
+/*
+ * Suited for:
+ * - ASUS A7V600-X: VIA KT600 + VT8237 + IT8712F
+ * - ASUS A7V8X-X: VIA KT400 + VT8235 + IT8712F
+ */
+static int it8712f_gpio31_raise(void)
+{
+       return it87_gpio_set(32, 1);
+}
+
+/*
+ * Suited for:
+ * - ASUS P5N-D: NVIDIA MCP51 + IT8718F
+ * - ASUS P5N-E SLI: NVIDIA MCP51 + IT8718F
+ */
+static int it8718f_gpio63_raise(void)
+{
+       return it87_gpio_set(63, 1);
+}
+
+/*
+ * Suited for all boards with ambiguous DMI chassis information, which should be
+ * whitelisted because they are known to work:
+ * - MSC Q7 Tunnel Creek Module (Q7-TCTC)
+ */
+static int p2_not_a_laptop(void)
+{
+       /* label this board as not a laptop */
+       is_laptop = 0;
+       msg_pdbg("Laptop detection overridden by P2 board enable.\n");
+       return 0;
+}
+
+#endif
+
+/*
+ * 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 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
+ * legacy bios is installed and when autodetection is not possible, these ids
+ * can be used to identify the board through the -p internal:mainboard=
+ * programmer parameter.
+ *
+ * When a board is identified through its coreboot ids (in both cases), the
+ * main pci ids are still required to match, as a safeguard.
+ */
+
+/* Please keep this list alphabetically ordered by vendor/board name. */
+const struct board_match board_matches[] = {
+
+       /* first pci-id set [4],          second pci-id set [4],          dmi identifier, coreboot id [2],  phase, vendor name,  board name       max_rom_...  OK? flash enable */
+#if defined(__i386__) || defined(__x86_64__)
+       {0x10DE, 0x0547, 0x147B, 0x1C2F,  0x10DE, 0x0548, 0x147B, 0x1C2F, NULL,         NULL, NULL,           P3, "abit",        "AN-M2",                 0,   NT, nvidia_mcp_gpio2_raise},
+       {0x1106, 0x0282, 0x147B, 0x1415,  0x1106, 0x3227, 0x147B, 0x1415, "^AV8 ",      NULL, NULL,           P3, "abit",        "AV8",                   0,   OK, board_abit_av8},
+       {0x8086, 0x7190,      0,      0,  0x8086, 0x7110,      0,      0, "^i440BX-W977 (BM6)$", NULL, NULL,  P3, "abit",        "BM6",                   0,   OK, intel_piix4_gpo26_lower},
+       {0x8086, 0x24d3, 0x147b, 0x1014,  0x8086, 0x2578, 0x147b, 0x1014, NULL,         NULL, NULL,           P3, "abit",        "IC7",                   0,   NT, intel_ich_gpio23_raise},
+       {0x8086, 0x2930, 0x147b, 0x1084,  0x11ab, 0x4364, 0x147b, 0x1084, NULL,         NULL, NULL,           P3, "abit",        "IP35",                  0,   OK, intel_ich_gpio16_raise},
+       {0x8086, 0x2930, 0x147b, 0x1083,  0x10ec, 0x8167, 0x147b, 0x1083, NULL,         NULL, NULL,           P3, "abit",        "IP35 Pro",              0,   OK, intel_ich_gpio16_raise},
+       {0x10de, 0x0050, 0x147b, 0x1c1a,       0,      0,      0,      0, NULL,         NULL, NULL,           P3, "abit",        "KN8 Ultra",             0,   NT, nvidia_mcp_gpio2_lower},
+       {0x10de, 0x01e0, 0x147b, 0x1c00,  0x10de, 0x0060, 0x147B, 0x1c00, NULL,         NULL, NULL,           P3, "abit",        "NF7-S",                 0,   OK, nvidia_mcp_gpio8_raise},
+       {0x10de, 0x02f0, 0x147b, 0x1c26,  0x10de, 0x0260, 0x147b, 0x1c26, NULL,         NULL, NULL,           P3, "abit",        "NF-M2 nView",           0,   OK, nvidia_mcp_gpio4_lower},
+       {0x1106, 0x0691,      0,      0,  0x1106, 0x3057,      0,      0, "(VA6)$",     NULL, NULL,           P3, "abit",        "VA6",                   0,   OK, via_apollo_gpo4_lower},
+       {0x1106, 0x0691,      0,      0,  0x1106, 0x3057,      0,      0, NULL,         "abit", "vt6x4",      P3, "abit",        "VT6X4",                 0,   OK, via_apollo_gpo4_lower},
+       {0x105a, 0x0d30, 0x105a, 0x4d33,  0x8086, 0x1130, 0x8086,      0, NULL,         NULL, NULL,           P3, "Acorp",       "6A815EPD",              0,   OK, board_acorp_6a815epd},
+       {0x1022, 0x746B,      0,      0,       0,      0,      0,      0, NULL,         "AGAMI", "ARUMA",     P3, "agami",       "Aruma",                 0,   OK, w83627hf_gpio24_raise_2e},
+       {0x1106, 0x3177, 0x17F2, 0x3177,  0x1106, 0x3148, 0x17F2, 0x3148, NULL,         NULL, NULL,           P3, "Albatron",    "PM266A Pro",            0,   OK, w836xx_memw_enable_2e},
+       {0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, NULL,        "artecgroup", "dbe61", P3, "Artec Group", "DBE61",                 0,   OK, board_artecgroup_dbe6x},
+       {0x1022, 0x2090,      0,      0,  0x1022, 0x2080,      0,      0, NULL,        "artecgroup", "dbe62", P3, "Artec Group", "DBE62",                 0,   OK, board_artecgroup_dbe6x},
+       {0x8086, 0x27b9, 0xa0a0, 0x0632,  0x8086, 0x27da, 0xa0a0, 0x0632, NULL,         NULL, NULL,           P3, "AOpen",       "i945GMx-VFX",           0,   OK, intel_ich_gpio38_raise},
+       {0x8086, 0x277c, 0xa0a0, 0x060b,  0x8086, 0x27da, 0xa0a0, 0x060b, NULL,         NULL, NULL,           P3, "AOpen",       "i975Xa-YDG",            0,   OK, board_aopen_i975xa_ydg},
+       {0x8086, 0x27b8, 0x1849, 0x27b8,  0x8086, 0x27da, 0x1849, 0x27da, "^ConRoeXFire-eSATA2", NULL, NULL,  P3, "ASRock",      "ConRoeXFire-eSATA2",    0,   OK, intel_ich_gpio16_raise},
+       {0x1039, 0x0741, 0x1849, 0x0741,  0x1039, 0x5513, 0x1849, 0x5513, "^K7S41 $",   NULL, NULL,           P3, "ASRock",      "K7S41",                 0,   OK, w836xx_memw_enable_2e},
+       {0x1039, 0x0741, 0x1849, 0x0741,  0x1039, 0x5513, 0x1849, 0x5513, "^K7S41GX$",  NULL, NULL,           P3, "ASRock",      "K7S41GX",               0,   OK, w836xx_memw_enable_2e},
+       {0x8086, 0x24D4, 0x1849, 0x24D0,  0x8086, 0x24D5, 0x1849, 0x9739, NULL,         NULL, NULL,           P3, "ASRock",      "P4i65GV",               0,   OK, intel_ich_gpio23_raise},
+       {0x8086, 0x2570, 0x1849, 0x2570,  0x8086, 0x24d3, 0x1849, 0x24d0, NULL,         NULL, NULL,           P3, "ASRock",      "775i65G",               0,   OK, intel_ich_gpio23_raise},
+       {0x10DE, 0x0060, 0x1043, 0x80AD,  0x10DE, 0x01E0, 0x1043, 0x80C0, NULL,         NULL, NULL,           P3, "ASUS",        "A7N8X-VM/400",          0,   OK, it8712f_gpio12_raise},
+       {0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3065, 0x1043, 0x80ED, NULL,         NULL, NULL,           P3, "ASUS",        "A7V600-X",              0,   OK, it8712f_gpio31_raise},
+       {0x1106, 0x3177, 0x1043, 0x80A1,  0x1106, 0x3205, 0x1043, 0x8118, NULL,         NULL, NULL,           P3, "ASUS",        "A7V8X-MX SE",           0,   OK, w836xx_memw_enable_2e},
+       {0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3177, 0x1043, 0x808C, NULL,         NULL, NULL,           P3, "ASUS",        "A7V8X",                 0,   OK, it8703f_gpio51_raise},
+       {0x1106, 0x3099, 0x1043, 0x807F,  0x1106, 0x3147, 0x1043, 0x808C, NULL,         NULL, NULL,           P3, "ASUS",        "A7V333",                0,   OK, it8703f_gpio51_raise},
+       {0x1106, 0x3189, 0x1043, 0x807F,  0x1106, 0x3177, 0x1043, 0x80A1, NULL,         NULL, NULL,           P3, "ASUS",        "A7V8X-X",               0,   OK, it8712f_gpio31_raise},
+       {0x1002, 0x4372, 0x103c, 0x2a26,  0x1002, 0x4377, 0x103c, 0x2a26, NULL,         NULL, NULL,           P3, "ASUS",        "A8AE-LE",               0,   OK, amd_sbxxx_gpio9_raise},
+       {0x8086, 0x27A0, 0x1043, 0x1287,  0x8086, 0x27DF, 0x1043, 0x1287, "^A8J",       NULL, NULL,           P3, "ASUS",        "A8Jm",                  0,   NT, intel_ich_gpio34_raise},
+       {0x10DE, 0x0260, 0x103C, 0x2A34,  0x10DE, 0x0264, 0x103C, 0x2A34, "NODUSM3",    NULL, NULL,           P3, "ASUS",        "A8M2N-LA (NodusM3-GL8E)",  0,   OK, nvidia_mcp_gpio0_raise},
+       {0x10DE, 0x0260, 0x103c, 0x2a3e,  0x10DE, 0x0264, 0x103c, 0x2a3e, "NAGAMI2L",   NULL, NULL,           P3, "ASUS",        "A8N-LA (Nagami-GL8E)",  0,   OK, nvidia_mcp_gpio0_raise},
+       {0x10DE, 0x005E, 0x1043, 0x815A,  0x10DE, 0x0054, 0x1043, 0x815A, "^A8N-SLI DELUXE", NULL, NULL,      P3, "ASUS",        "A8N-SLI Deluxe",        0,   NT, board_shuttle_fn25},
+       {0x10de, 0x0264, 0x1043, 0x81bc,  0x10de, 0x02f0, 0x1043, 0x81cd, NULL,         NULL, NULL,           P3, "ASUS",        "A8N-VM CSM",            0,   OK, w83627ehf_gpio22_raise_2e},
+       {0x10DE, 0x0264, 0x1043, 0x81C0,  0x10DE, 0x0260, 0x1043, 0x81C0, NULL,         NULL, NULL,           P3, "ASUS",        "M2NBP-VM CSM",          0,   OK, nvidia_mcp_gpio0_raise},
+       {0x1106, 0x1336, 0x1043, 0x80ed,  0x1106, 0x3288, 0x1043, 0x8249, NULL,         NULL, NULL,           P3, "ASUS",        "M2V-MX",                0,   OK, via_vt823x_gpio5_raise},
+       {0x8086, 0x24cc,      0,      0,  0x8086, 0x24c3, 0x1043, 0x1869, "^M6Ne$",     NULL, NULL,           P3, "ASUS",        "M6Ne",                  0,   NT, intel_ich_gpio43_raise},
+       {0x8086, 0x7180,      0,      0,  0x8086, 0x7110,      0,      0, "^OPLX-M$",   NULL, NULL,           P3, "ASUS",        "OPLX-M",                0,   NT, intel_piix4_gpo18_lower},
+       {0x8086, 0x7190,      0,      0,  0x8086, 0x7110,      0,      0, "^P2B-N$",    NULL, NULL,           P3, "ASUS",        "P2B-N",                 0,   OK, intel_piix4_gpo18_lower},
+       {0x8086, 0x1A30, 0x1043, 0x8025,  0x8086, 0x244B, 0x104D, 0x80F0, NULL,         NULL, NULL,           P3, "ASUS",        "P4B266-LM",             0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x1a30, 0x1043, 0x8070,  0x8086, 0x244b, 0x1043, 0x8028, NULL,         NULL, NULL,           P3, "ASUS",        "P4B266",                0,   OK, intel_ich_gpio22_raise},
+       {0x8086, 0x1A30, 0x1043, 0x8088,  0x8086, 0x24C3, 0x1043, 0x8089, NULL,         NULL, NULL,           P3, "ASUS",        "P4B533-E",              0,   NT, intel_ich_gpio22_raise},
+       {0x8086, 0x2560, 0x103C, 0x2A00,  0x8086, 0x24C3, 0x103C, 0x2A01, "^Guppy",     NULL, NULL,           P3, "ASUS",        "P4GV-LA (Guppy)",       0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x24D3, 0x1043, 0x80A6,  0x8086, 0x2578, 0x1043, 0x80F6, NULL,         NULL, NULL,           P3, "ASUS",        "P4C800-E Deluxe",       0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x2570, 0x1043, 0x80F2,  0x8086, 0x24D5, 0x1043, 0x80F3, NULL,         NULL, NULL,           P3, "ASUS",        "P4P800",                0,   NT, intel_ich_gpio21_raise},
+       {0x8086, 0x2570, 0x1043, 0x80F2,  0x8086, 0x24D3, 0x1043, 0x80A6, "^P4P800-E$", NULL, NULL,           P3, "ASUS",        "P4P800-E Deluxe",       0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x2570, 0x1043, 0x80A5,  0x8086, 0x24d0,      0,      0, NULL,         NULL, NULL,           P3, "ASUS",        "P4P800-VM",             0,   OK, intel_ich_gpio21_raise},
+       {0x1039, 0x0651, 0x1043, 0x8081,  0x1039, 0x0962,      0,      0, NULL,         NULL, NULL,           P3, "ASUS",        "P4SC-E",                0,   OK, it8707f_write_enable_2e},
+       {0x8086, 0x2570, 0x1043, 0x80A5,  0x105A, 0x24D3, 0x1043, 0x80A6, NULL,         NULL, NULL,           P3, "ASUS",        "P4SD-LA",               0,   NT, intel_ich_gpio32_raise},
+       {0x1039, 0x0661, 0x1043, 0x8113,  0x1039, 0x5513, 0x1043, 0x8087, NULL,         NULL, NULL,           P3, "ASUS",        "P4S800-MX",             512, OK, w836xx_memw_enable_2e},
+       {0x10B9, 0x1541,      0,      0,  0x10B9, 0x1533,      0,      0, "^P5A$",      "asus", "p5a",        P3, "ASUS",        "P5A",                   0,   OK, board_asus_p5a},
+       {0x8086, 0x27b8, 0x1043, 0x819e,  0x8086, 0x29f0, 0x1043, 0x82a5, "^P5BV-R$",   NULL, NULL,           P3, "ASUS",        "P5BV-R",                0,   OK, intel_ich_gpio20_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x814e, "^P5GD1 PRO$", NULL, NULL,          P3, "ASUS",        "P5GD1 Pro",             0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x814e, "^P5GD1-VM$", NULL, NULL,           P3, "ASUS",        "P5GD1-VM/S",            0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x814e, NULL,         NULL, NULL,           P3, "ASUS",        "P5GD1(-VM)",            0,   NT, intel_ich_gpio21_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x813d, "^P5GD2-Premium$", NULL, NULL,      P3, "ASUS",        "P5GD2 Premium",         0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x81a6, "^P5GD2-X$",  NULL, NULL,           P3, "ASUS",        "P5GD2-X",               0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x813d, "^P5GDC-V$",  NULL, NULL,           P3, "ASUS",        "P5GDC-V Deluxe",        0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x813d, "^P5GDC$",    NULL, NULL,           P3, "ASUS",        "P5GDC Deluxe",          0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x266a, 0x1043, 0x80a6,  0x8086, 0x2668, 0x1043, 0x813d, NULL,         NULL, NULL,           P3, "ASUS",        "P5GD2/C variants",      0,   NT, intel_ich_gpio21_raise},
+       {0x8086, 0x27b8, 0x103c, 0x2a22,  0x8086, 0x2770, 0x103c, 0x2a22, "^LITHIUM$",  NULL, NULL,           P3, "ASUS",        "P5LP-LE (Lithium-UL8E)",0,   OK, intel_ich_gpio34_raise},
+       {0x8086, 0x27b8, 0x1043, 0x2a22,  0x8086, 0x2770, 0x1043, 0x2a22, "^P5LP-LE$",  NULL, NULL,           P3, "ASUS",        "P5LP-LE (Epson OEM)",   0,   OK, intel_ich_gpio34_raise},
+       {0x8086, 0x27da, 0x1043, 0x8179,  0x8086, 0x27b8, 0x1043, 0x8179, "^P5LD2$",    NULL, NULL,           P3, "ASUS",        "P5LD2",                 0,   NT, intel_ich_gpio16_raise},
+       {0x10DE, 0x0030, 0x1043, 0x818a,  0x8086, 0x100E, 0x1043, 0x80EE, NULL,         NULL, NULL,           P3, "ASUS",        "P5ND2-SLI Deluxe",      0,   OK, nvidia_mcp_gpio10_raise},
+       {0x10DE, 0x0260, 0x1043, 0x81BC,  0x10DE, 0x026C, 0x1043, 0x829E, "^P5N-D$",    NULL, NULL,           P3, "ASUS",        "P5N-D",                 0,   OK, it8718f_gpio63_raise},
+       {0x10DE, 0x0260, 0x1043, 0x81BC,  0x10DE, 0x026C, 0x1043, 0x8249, "^P5N-E SLI$",NULL, NULL,           P3, "ASUS",        "P5N-E SLI",             0,   NT, it8718f_gpio63_raise},
+       {0x8086, 0x24dd, 0x1043, 0x80a6,  0x8086, 0x2570, 0x1043, 0x8157, NULL,         NULL, NULL,           P3, "ASUS",        "P5PE-VM",               0,   OK, intel_ich_gpio21_raise},
+       {0x8086, 0x2443, 0x1043, 0x8027,  0x8086, 0x1130, 0x1043, 0x8027, NULL,         NULL, NULL,           P3, "ASUS",        "TUSL2-C",               0,   NT, intel_ich_gpio21_raise},
+       {0x10b7, 0x9055, 0x1028, 0x0082,  0x8086, 0x7190,      0,      0, NULL,         NULL, NULL,           P3, "Dell",        "OptiPlex GX1",          0,   OK, intel_piix4_gpo30_lower},
+       {0x8086, 0x3590, 0x1028, 0x016c,  0x1000, 0x0030, 0x1028, 0x016c, NULL,         NULL, NULL,           P3, "Dell",        "PowerEdge 1850",        0,   OK, intel_ich_gpio23_raise},
+       {0x10de, 0x03ea, 0x1019, 0x2602,  0x10de, 0x03e0, 0x1019, 0x2602, NULL,         NULL, NULL,           P3, "Elitegroup",  "GeForce6100SM-M",       0,   OK, board_ecs_geforce6100sm_m},
+       {0x1106, 0x3038, 0x1019, 0x0996,  0x1106, 0x3177, 0x1019, 0x0996, NULL,         NULL, NULL,           P3, "Elitegroup",  "K7VTA3",                256, OK, NULL},
+       {0x1106, 0x3177, 0x1106, 0x3177,  0x1106, 0x3059, 0x1695, 0x3005, NULL,         NULL, NULL,           P3, "EPoX",        "EP-8K5A2",              0,   OK, w836xx_memw_enable_2e},
+       {0x10DE, 0x005E, 0x1695, 0x1010,  0x10DE, 0x0050, 0x1695, 0x1010, "8NPA7I",     NULL, NULL,           P3, "EPoX",        "EP-8NPA7I",             0,   OK, nvidia_mcp_gpio4_raise},
+       {0x10DE, 0x005E, 0x1695, 0x1010,  0x10DE, 0x0050, 0x1695, 0x1010, "9NPA7I",     NULL, NULL,           P3, "EPoX",        "EP-9NPA7I",             0,   OK, nvidia_mcp_gpio4_raise},
+       {0x10EC, 0x8139, 0x1695, 0x9001,  0x11C1, 0x5811, 0x1695, 0x9015, NULL,         NULL, NULL,           P3, "EPoX",        "EP-8RDA3+",             0,   OK, nvidia_mcp_gpio31_raise},
+       {0x8086, 0x7110,      0,      0,  0x8086, 0x7190,      0,      0, NULL,         "epox", "ep-bx3",     P3, "EPoX",        "EP-BX3",                0,   NT, intel_piix4_gpo22_raise},
+       {0x10de, 0x02f0, 0x105b, 0x0d01,  0x10de, 0x0264, 0x105b, 0x0d01, NULL,         NULL, NULL,           P3, "Foxconn",     "6150K8MD-8EKRSH",       0,   NT, nvidia_mcp_gpio2_raise},
+       {0x8086, 0x2443, 0x8086, 0x2442,  0x8086, 0x1130, 0x8086, 0x1130, "^6IEM ",     NULL, NULL,           P3, "GIGABYTE",    "GA-6IEM",               0,   NT, intel_ich_gpio25_raise},
+       {0x1106, 0x0686, 0x1106, 0x0686,  0x1106, 0x3058, 0x1458, 0xa000, NULL,         NULL, NULL,           P3, "GIGABYTE",    "GA-7ZM",                512, OK, NULL},
+       {0x8086, 0x2570, 0x1458, 0x2570,  0x8086, 0x24d0,      0,      0, "^8IP775/-G$",NULL, NULL,           P3, "GIGABYTE",    "GA-8IP775",             0,   OK, intel_ich_gpio32_raise},
+       {0x8086, 0x244b, 0x8086, 0x2442,  0x8086, 0x2445, 0x1458, 0xa002, NULL,         NULL, NULL,           P3, "GIGABYTE",    "GA-8IRML",              0,   OK, intel_ich_gpio25_raise},
+       {0x8086, 0x24c3, 0x1458, 0x24c2,  0x8086, 0x24cd, 0x1458, 0x5004, NULL,         NULL, NULL,           P3, "GIGABYTE",    "GA-8PE667 Ultra 2",     0,   OK, intel_ich_gpio32_raise},
+       {0x1039, 0x0651, 0x1039, 0x0651,  0x1039, 0x7002, 0x1458, 0x5004, "^GA-8SIMLH$",NULL, NULL,           P3, "GIGABYTE",    "GA-8SIMLH",             0,   OK, sis_gpio0_raise_and_w836xx_memw},
+       {0x10DE, 0x02F1, 0x1458, 0x5000,  0x10DE, 0x0261, 0x1458, 0x5001, NULL,         NULL, NULL,           P3, "GIGABYTE",    "GA-K8N51GMF",           0,   OK, nvidia_mcp_gpio3b_raise},
+       {0x10DE, 0x026C, 0x1458, 0xA102,  0x10DE, 0x0260, 0x1458, 0x5001, NULL,         NULL, NULL,           P3, "GIGABYTE",    "GA-K8N51GMF-9",         0,   OK, nvidia_mcp_gpio3b_raise},
+       {0x10de, 0x00e4, 0x1458, 0x0c11,  0x10de, 0x00e0, 0x1458, 0x0c11, NULL,         NULL, NULL,           P3, "GIGABYTE",    "GA-K8NS Pro-939",       0,   NT, nvidia_mcp_gpio0a_raise},
+       {0x10DE, 0x0050, 0x1458, 0x0C11,  0x10DE, 0x005e, 0x1458, 0x5000, NULL,         NULL, NULL,           P3, "GIGABYTE",    "GA-K8N-SLI",            0,   OK, nvidia_mcp_gpio21_raise},
+       {0x8086, 0x2415, 0x103c, 0x1250,  0x10b7, 0x9200, 0x103c, 0x1247, NULL,         NULL, NULL,           P3, "HP",          "e-Vectra P2706T",       0,   OK, board_hp_p2706t},
+       {0x1166, 0x0223, 0x103c, 0x320d,  0x14e4, 0x1678, 0x103c, 0x703e, NULL,         "hp", "dl145_g3",     P3, "HP",          "ProLiant DL145 G3",     0,   OK, board_hp_dl145_g3_enable},
+       {0x1166, 0x0223, 0x103c, 0x320d,  0x14e4, 0x1648, 0x103c, 0x310f, NULL,         "hp", "dl165_g6",     P3, "HP",          "ProLiant DL165 G6",     0,   OK, board_hp_dl165_g6_enable},
+       {0x8086, 0x2580, 0x103c, 0x2a08,  0x8086, 0x2640, 0x103c, 0x2a0a, NULL,         NULL, NULL,           P3, "HP",          "Puffer2-UL8E",          0,   OK, intel_ich_gpio18_raise},
+       {0x8086, 0x2415, 0x103c, 0x1249,  0x10b7, 0x9200, 0x103c, 0x1246, NULL,         NULL, NULL,           P3, "HP",          "Vectra VL400",          0,   OK, board_hp_vl400},
+       {0x8086, 0x1a30, 0x103c, 0x1a30,  0x8086, 0x2443, 0x103c, 0x2440, "^VL420$",    NULL, NULL,           P3, "HP",          "Vectra VL420 SFF",      0,   OK, intel_ich_gpio22_raise},
+       {0x10de, 0x0369, 0x103c, 0x12fe,  0x10de, 0x0364, 0x103c, 0x12fe, NULL,         "hp", "xw9400",       P3, "HP",          "xw9400",                0,   OK, nvidia_mcp_gpio5_raise},
+       {0x8086, 0x27A0,      0,      0,  0x8086, 0x27B9,      0,      0, NULL,         "ibase", "mb899",     P3, "IBASE",       "MB899",                 0,   OK, intel_ich_gpio26_raise},
+       {0x1166, 0x0205, 0x1014, 0x0347,  0x1002, 0x515E, 0x1014, 0x0325, NULL,         NULL, NULL,           P3, "IBM",         "x3455",                 0,   OK, board_ibm_x3455},
+       {0x1039, 0x5513, 0x8086, 0xd61f,  0x1039, 0x6330, 0x8086, 0xd61f, NULL,         NULL, NULL,           P3, "Intel",       "D201GLY",               0,   OK, wbsio_check_for_spi},
+       {0x8086, 0x7190,      0,      0,  0x8086, 0x7110,      0,      0, "^SE440BX-2$", NULL, NULL,          P3, "Intel",       "SE440BX-2",             0,   NT, intel_piix4_gpo27_lower},
+       {0x1022, 0x7468,      0,      0,       0,      0,      0,      0, NULL,         "iwill", "dk8_htx",   P3, "IWILL",       "DK8-HTX",               0,   OK, w83627hf_gpio24_raise_2e},
+       {0x8086, 0x27A0, 0x8086, 0x27a0,  0x8086, 0x27b8, 0x8086, 0x27b8, NULL,        "kontron", "986lcd-m", P3, "Kontron",     "986LCD-M",              0,   OK, board_kontron_986lcd_m},
+       {0x8086, 0x2411, 0x8086, 0x2411,  0x8086, 0x7125, 0x0e11, 0xb165, NULL,         NULL, NULL,           P3, "Mitac",       "6513WU",                0,   OK, board_mitac_6513wu},
+       {0x8086, 0x8186, 0x8086, 0x8186,  0x8086, 0x8800, 0x0000, 0x0000, "^MSC Vertriebs GmbH$", NULL, NULL, P2, "MSC",         "Q7-TCTC",               0,   OK, p2_not_a_laptop},
+       {0x10DE, 0x005E, 0x1462, 0x7125,  0x10DE, 0x0052, 0x1462, 0x7125, NULL,         NULL, NULL,           P3, "MSI",         "K8N Neo4-F",            0,   OK, nvidia_mcp_gpio2_raise}, /* TODO: Should probably be K8N Neo4 Platinum, see http://www.coreboot.org/pipermail/flashrom/2010-August/004362.html. */
+       {0x8086, 0x7190,      0,      0,  0x8086, 0x7110,      0,      0, "^MS-6163 (i440BX)$", NULL, NULL,   P3, "MSI",         "MS-6163 (MS-6163 Pro)", 0,   OK, intel_piix4_gpo14_raise},
+       {0x1039, 0x0745,      0,      0,  0x1039, 0x0018,      0,      0, "^MS-6561",   NULL, NULL,           P3, "MSI",         "MS-6561 (745 Ultra)",   0,   OK, w836xx_memw_enable_2e},
+       {0x8086, 0x2560, 0x1462, 0x5770,  0x8086, 0x2562, 0x1462, 0x5778, NULL,         NULL, NULL,           P3, "MSI",         "MS-6577 (Xenon)",       0,   OK, w83627hf_gpio25_raise_2e},
+       {0x13f6, 0x0111, 0x1462, 0x5900,  0x1106, 0x3177, 0x1106,      0, NULL,         NULL, NULL,           P3, "MSI",         "MS-6590 (KT4 Ultra)",   0,   OK, board_msi_kt4v},
+       {0x1106, 0x3149, 0x1462, 0x7094,  0x10ec, 0x8167, 0x1462, 0x094c, NULL,         NULL, NULL,           P3, "MSI",         "MS-6702E (K8T Neo2-F)", 0,   OK, w83627thf_gpio44_raise_2e},
+       {0x1106, 0x0571, 0x1462, 0x7120,  0x1106, 0x3065, 0x1462, 0x7120, NULL,         NULL, NULL,           P3, "MSI",         "MS-6712 (KT4V)",        0,   OK, board_msi_kt4v},
+       {0x1106, 0x3148, 0     , 0     ,  0x1106, 0x3177, 0     , 0     , NULL,         "msi", "ms6787",      P3, "MSI",         "MS-6787 (P4MAM-V/P4MAM-L)", 0, OK, w836xx_memw_enable_2e},
+       {0x8086, 0x24d3, 0x1462, 0x7880,  0x8086, 0x2570,      0,      0, NULL,         NULL, NULL,           P3, "MSI",         "MS-6788-040 (848P NeoV)", 0, OK, intel_ich_gpio32_raise},
+       {0x1039, 0x7012, 0x1462, 0x0050,  0x1039, 0x6325, 0x1462, 0x0058, NULL,         NULL, NULL,           P3, "MSI",         "MS-7005 (651M-L)",      0,   OK, sis_gpio0_raise_and_w836xx_memw},
+       {0x10DE, 0x00E0, 0x1462, 0x0250,  0x10DE, 0x00E1, 0x1462, 0x0250, NULL,         NULL, NULL,           P3, "MSI",         "MS-7025 (K8N Neo2 Platinum)", 0, OK, nvidia_mcp_gpio0c_raise},
+       {0x8086, 0x2658, 0x1462, 0x7046,  0x1106, 0x3044, 0x1462, 0x046d, NULL,         NULL, NULL,           P3, "MSI",         "MS-7046",               0,   OK, intel_ich_gpio19_raise},
+       {0x8086, 0x244b, 0x1462, 0x3910,  0x8086, 0x2442, 0x1462, 0x3910, NULL,         NULL, NULL,           P3, "MSI",         "MS-6391 (845 Pro4)",    0,   OK, intel_ich_gpio23_raise},
+       {0x1106, 0x3149, 0x1462, 0x7061,  0x1106, 0x3227,      0,      0, NULL,         NULL, NULL,           P3, "MSI",         "MS-7061 (KM4M-V/KM4AM-V)", 0, OK, w836xx_memw_enable_2e},
+       {0x10DE, 0x005E, 0x1462, 0x7135,  0x10DE, 0x0050, 0x1462, 0x7135, NULL,         "msi", "k8n-neo3",    P3, "MSI",         "MS-7135 (K8N Neo3)",    0,   OK, w83627thf_gpio44_raise_4e},
+       {0x10DE, 0x0270, 0x1462, 0x7207,  0x10DE, 0x0264, 0x1462, 0x7207, NULL,         NULL, NULL,           P3, "MSI",         "MS-7207 (K8NGM2-L)",    0,   NT, nvidia_mcp_gpio2_raise},
+       {0x10DE, 0x0360, 0x1462, 0x7250,  0x10DE, 0x0368, 0x1462, 0x7250, NULL,         NULL, NULL,           P3, "MSI",         "MS-7250 (K9N SLI)",     0,   OK, nvidia_mcp_gpio2_raise},
+       {0x1011, 0x0019, 0xaa55, 0xaa55,  0x8086, 0x7190,      0,      0, NULL,         NULL, NULL,           P3, "Nokia",       "IP530",                 0,   OK, fdc37b787_gpio50_raise_3f0},
+       {0x8086, 0x24d3, 0x144d, 0xb025,  0x8086, 0x1050, 0x144d, 0xb025, NULL,         NULL, NULL,           P3, "Samsung",     "Polaris 32",            0,   OK, intel_ich_gpio21_raise},
+       {0x1106, 0x3099,      0,      0,  0x1106, 0x3074,      0,      0, NULL,         "shuttle", "ak31",    P3, "Shuttle",     "AK31",                  0,   OK, w836xx_memw_enable_2e},
+       {0x1106, 0x3104, 0x1297, 0xa238,  0x1106, 0x3059, 0x1297, 0xc063, NULL,         NULL, NULL,           P3, "Shuttle",     "AK38N",                 256, OK, NULL},
+       {0x10DE, 0x0050, 0x1297, 0x5036,  0x1412, 0x1724, 0x1297, 0x5036, NULL,         NULL, NULL,           P3, "Shuttle",     "FN25",                  0,   OK, board_shuttle_fn25},
+       {0x1106, 0x3038, 0x0925, 0x1234,  0x1106, 0x3058, 0x15DD, 0x7609, NULL,         NULL, NULL,           P3, "Soyo",        "SY-7VCA",               0,   OK, via_apollo_gpo0_lower},
+       {0x10de, 0x0364, 0x108e, 0x6676,  0x10de, 0x0369, 0x108e, 0x6676, "^Sun Ultra 40 M2", NULL, NULL,     P3, "Sun",         "Ultra 40 M2",           0,   OK, board_sun_ultra_40_m2},
+       {0x1106, 0x3038, 0x0925, 0x1234,  0x1106, 0x0596, 0x1106,      0, NULL,         NULL, NULL,           P3, "Tekram",      "P6Pro-A5",              256, OK, NULL},
+       {0x1106, 0x3123, 0x1106, 0x3123,  0x1106, 0x3059, 0x1106, 0x4161, NULL,         NULL, NULL,           P3, "Termtek",     "TK-3370 (Rev:2.5B)",    0,   OK, w836xx_memw_enable_4e},
+       {0x8086, 0x7120, 0x109f, 0x3157,  0x8086, 0x2410,      0,      0, NULL,         NULL, NULL,           P3, "TriGem",      "Anaheim-3",             0,   OK, intel_ich_gpio22_raise},
+       {0x8086, 0x1076, 0x8086, 0x1176,  0x1106, 0x3059, 0x10f1, 0x2498, NULL,         NULL, NULL,           P3, "Tyan",        "S2498 (Tomcat K7M)",    0,   OK, w836xx_memw_enable_2e},
+       {0x1106, 0x0259, 0x1106, 0xAA07,  0x1106, 0x3227, 0x1106, 0xAA07, NULL,         NULL, NULL,           P3, "VIA",         "EPIA EK",               0,   NT, via_vt823x_gpio9_raise},
+       {0x1106, 0x3177, 0x1106, 0xAA01,  0x1106, 0x3123, 0x1106, 0xAA01, NULL,         NULL, NULL,           P3, "VIA",         "EPIA M/MII/...",        0,   OK, via_vt823x_gpio15_raise},
+       {0x1106, 0x0259, 0x1106, 0x3227,  0x1106, 0x3065, 0x1106, 0x3149, NULL,         NULL, NULL,           P3, "VIA",         "EPIA-N/NL",             0,   OK, via_vt823x_gpio9_raise},
+#endif
+       {     0,      0,      0,      0,       0,      0,      0,      0, NULL,         NULL, NULL,           P3, NULL,          NULL,                    0,   NT, NULL}, /* end marker */
+};
+
+/*
+ * Match boards on coreboot table gathered vendor and part name.
+ * Require main PCI IDs to match too as extra safety.
+ */
+static const struct board_match *board_match_cbname(const char *vendor,
+                                                   const char *part)
+{
+       const struct board_match *board = board_matches;
+       const struct board_match *partmatch = NULL;
+
+       for (; board->vendor_name; board++) {
+               if (vendor && (!board->lb_vendor
+                              || strcasecmp(board->lb_vendor, vendor)))
+                       continue;
+
+               if (!board->lb_part || strcasecmp(board->lb_part, part))
+                       continue;
+
+               if (!pci_dev_find(board->first_vendor, board->first_device))
+                       continue;
+
+               if (board->second_vendor &&
+                   !pci_dev_find(board->second_vendor, board->second_device))
+                       continue;
+
+               if (vendor)
+                       return board;
+
+               if (partmatch) {
+                       /* a second entry has a matching part name */
+                       msg_pinfo("AMBIGUOUS BOARD NAME: %s\n", part);
+                       msg_pinfo("At least vendors '%s' and '%s' match.\n",
+                                 partmatch->lb_vendor, board->lb_vendor);
+                       msg_perr("Please use the full -p internal:mainboard="
+                                "vendor:part syntax.\n");
+                       return NULL;
+               }
+               partmatch = board;
+       }
+
+       if (partmatch)
+               return partmatch;
+
+       if (!partvendor_from_cbtable) {
+               /* Only warn if the mainboard type was not gathered from the
+                * coreboot table. If it was, the coreboot implementor is
+                * expected to fix flashrom, too.
+                */
+               msg_perr("\nUnknown vendor:board from -p internal:mainboard="
+                        " programmer parameter:\n%s:%s\n\n",
+                        vendor, part);
+       }
+       return NULL;
+}
+
+/*
+ * Match boards on PCI IDs and subsystem IDs.
+ * Second set of IDs can be either main+subsystem IDs, main IDs or no IDs.
+ */
+const static struct board_match *board_match_pci_ids(enum board_match_phase phase)
+{
+       const struct board_match *board = board_matches;
+
+       for (; board->vendor_name; board++) {
+               if ((!board->first_card_vendor || !board->first_card_device) &&
+                     !board->dmi_pattern)
+                       continue;
+               if (board->phase != phase)
+                       continue;
+
+               if (!pci_card_find(board->first_vendor, board->first_device,
+                                  board->first_card_vendor,
+                                  board->first_card_device))
+                       continue;
+
+               if (board->second_vendor) {
+                       if (board->second_card_vendor) {
+                               if (!pci_card_find(board->second_vendor,
+                                                  board->second_device,
+                                                  board->second_card_vendor,
+                                                  board->second_card_device))
+                                       continue;
+                       } else {
+                               if (!pci_dev_find(board->second_vendor,
+                                                 board->second_device))
+                                       continue;
+                       }
+               }
+
+               if (board->dmi_pattern) {
+                       if (!has_dmi_support) {
+                               msg_perr("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;
+       }
+
+       return NULL;
+}
+
+static int unsafe_board_handler(const struct board_match *board)
+{
+       if (!board)
+               return 1;
+
+       if (board->status == OK)
+               return 0;
+
+       if (!force_boardenable) {
+               msg_pinfo("WARNING: Your mainboard is %s %s, but the mainboard-specific\n"
+                         "code has not been tested, and thus will 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);
+               return 1;
+       }
+       msg_pinfo("NOTE: Running an untested board enable procedure.\n"
+                 "Please report success/failure to flashrom@flashrom.org\n"
+                 "with your board name and SUCCESS or FAILURE in the subject.\n");
+       return 0;
+}
+
+/* FIXME: Should this be identical to board_flash_enable? */
+static int board_handle_phase(enum board_match_phase phase)
+{
+       const struct board_match *board = NULL;
+
+       board = board_match_pci_ids(phase);
+
+       if (unsafe_board_handler(board))
+               board = NULL;
+
+       if (!board)
+               return 0;
+
+       if (!board->enable) {
+               /* Not sure if there is a valid case for this. */
+               msg_perr("Board match found, but nothing to do?\n");
+               return 0;
+       }
+
+       return board->enable();
+}
+
+void board_handle_before_superio(void)
+{
+       board_handle_phase(P1);
+}
+
+void board_handle_before_laptop(void)
+{
+       board_handle_phase(P2);
+}
+
+int board_flash_enable(const char *vendor, const char *part)
+{
+       const struct board_match *board = NULL;
+       int ret = 0;
+
+       if (part)
+               board = board_match_cbname(vendor, part);
+
+       if (!board)
+               board = board_match_pci_ids(P3);
+
+       if (unsafe_board_handler(board))
+               board = NULL;
+
+       if (board) {
+               if (board->max_rom_decode_parallel)
+                       max_rom_decode.parallel =
+                               board->max_rom_decode_parallel * 1024;
+
+               if (board->enable != NULL) {
+                       msg_pinfo("Disabling flash write protection for "
+                                 "board \"%s %s\"... ", board->vendor_name,
+                                 board->board_name);
+
+                       ret = board->enable();
+                       if (ret)
+                               msg_pinfo("FAILED!\n");
+                       else
+                               msg_pinfo("OK.\n");
+               }
+       }
+
+       return ret;
+}
diff --git a/buspirate_spi.c b/buspirate_spi.c
new file mode 100644 (file)
index 0000000..a488fc3
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * 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; 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "flash.h"
+#include "programmer.h"
+#include "spi.h"
+
+/* Change this to #define if you want to test without a serial implementation */
+#undef FAKE_COMMUNICATION
+
+struct buspirate_spispeeds {
+       const char *name;
+       const int speed;
+};
+
+#ifndef FAKE_COMMUNICATION
+static int buspirate_serialport_setup(char *dev)
+{
+       /* 115200bps, 8 databits, no parity, 1 stopbit */
+       sp_fd = sp_openserport(dev, 115200);
+       if (sp_fd < 0)
+               return 1;
+       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
+
+static unsigned char *bp_commbuf = NULL;
+static int bp_commbufsize = 0;
+
+static int buspirate_commbuf_grow(int bufsize)
+{
+       unsigned char *tmpbuf;
+
+       /* Never shrink. realloc() calls are expensive. */
+       if (bufsize <= bp_commbufsize)
+               return 0;
+
+       tmpbuf = realloc(bp_commbuf, bufsize);
+       if (!tmpbuf) {
+               /* Keep the existing buffer because memory is already tight. */
+               msg_perr("Out of memory!\n");
+               return ERROR_OOM;
+       }
+
+       bp_commbuf = tmpbuf;
+       bp_commbufsize = bufsize;
+       return 0;
+}
+
+static 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 int buspirate_spi_send_command(struct flashctx *flash,
+                                     unsigned int writecnt,
+                                     unsigned int readcnt,
+                                     const unsigned char *writearr,
+                                     unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_buspirate = {
+       .type           = SPI_CONTROLLER_BUSPIRATE,
+       .max_data_read  = 12,
+       .max_data_write = 12,
+       .command        = buspirate_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = default_spi_read,
+       .write_256      = default_spi_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+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},
+};
+
+static int buspirate_spi_shutdown(void *data)
+{
+       int ret = 0, ret2 = 0;
+       /* No need to allocate a buffer here, we know that bp_commbuf is at least DEFAULT_BUFSIZE big. */
+
+       /* Exit raw SPI mode (enter raw bitbang mode) */
+       bp_commbuf[0] = 0x00;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 5);
+       if (ret)
+               goto out_shutdown;
+       if (memcmp(bp_commbuf, "BBIO", 4)) {
+               msg_perr("Entering raw bitbang mode failed!\n");
+               ret = 1;
+               goto out_shutdown;
+       }
+       msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[4]);
+       if (bp_commbuf[4] != '1') {
+               msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[4]);
+               ret = 1;
+               goto out_shutdown;
+       }
+       /* Reset Bus Pirate (return to user terminal) */
+       bp_commbuf[0] = 0x0f;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 0);
+
+out_shutdown:
+       /* Shut down serial port communication */
+       ret2 = serialport_shutdown(NULL);
+       /* Keep the oldest error, it is probably the best indicator. */
+       if (ret2 && !ret)
+               ret = ret2;
+       bp_commbufsize = 0;
+       free(bp_commbuf);
+       bp_commbuf = NULL;
+       if (ret)
+               msg_pdbg("Bus Pirate shutdown failed.\n");
+       else
+               msg_pdbg("Bus Pirate shutdown completed.\n");
+
+       return ret;
+}
+
+int buspirate_spi_init(void)
+{
+       char *dev = NULL;
+       char *speed = NULL;
+       int spispeed = 0x7;
+       int ret = 0;
+       int i;
+
+       dev = extract_programmer_param("dev");
+       if (!dev || !strlen(dev)) {
+               msg_perr("No serial device given. Use flashrom -p "
+                       "buspirate_spi:dev=/dev/ttyUSB0\n");
+               return 1;
+       }
+
+       speed = extract_programmer_param("spispeed");
+       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");
+       }
+       free(speed);
+
+       /* This works because speeds numbering starts at 0 and is contiguous. */
+       msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name);
+
+       /* Default buffer size is 19: 16 bytes data, 3 bytes control. */
+#define DEFAULT_BUFSIZE (16 + 3)
+       bp_commbuf = malloc(DEFAULT_BUFSIZE);
+       if (!bp_commbuf) {
+               bp_commbufsize = 0;
+               msg_perr("Out of memory!\n");
+               return ERROR_OOM;
+       }
+       bp_commbufsize = DEFAULT_BUFSIZE;
+
+       ret = buspirate_serialport_setup(dev);
+       free(dev);
+       if (ret) {
+               bp_commbufsize = 0;
+               free(bp_commbuf);
+               bp_commbuf = NULL;
+               return ret;
+       }
+
+       if (register_shutdown(buspirate_spi_shutdown, NULL))
+               return 1;
+
+       /* This is the brute force version, but it should work. */
+       for (i = 0; i < 19; i++) {
+               /* Enter raw bitbang mode */
+               bp_commbuf[0] = 0x00;
+               /* Send the command, don't read the response. */
+               ret = buspirate_sendrecv(bp_commbuf, 1, 0);
+               if (ret)
+                       return ret;
+               /* Read any response and discard it. */
+               sp_flush_incoming();
+       }
+       /* USB is slow. The Bus Pirate is even slower. Apparently the flush
+        * action above is too fast or too early. Some stuff still remains in
+        * the pipe after the flush above, and one additional flush is not
+        * sufficient either. Use a 1.5 ms delay inside the loop to make
+        * mostly sure that at least one USB frame had time to arrive.
+        * Looping only 5 times is not sufficient and causes the
+        * occasional failure.
+        * Folding the delay into the loop above is not reliable either.
+        */
+       for (i = 0; i < 10; i++) {
+               usleep(1500);
+               /* Read any response and discard it. */
+               sp_flush_incoming();
+       }
+       /* Enter raw bitbang mode */
+       bp_commbuf[0] = 0x00;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 5);
+       if (ret)
+               return ret;
+       if (memcmp(bp_commbuf, "BBIO", 4)) {
+               msg_perr("Entering raw bitbang mode failed!\n");
+               msg_pdbg("Got %02x%02x%02x%02x%02x\n",
+                        bp_commbuf[0], bp_commbuf[1], bp_commbuf[2],
+                        bp_commbuf[3], bp_commbuf[4]);
+               return 1;
+       }
+       msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[4]);
+       if (bp_commbuf[4] != '1') {
+               msg_perr("Can't handle raw bitbang mode version %c!\n",
+                       bp_commbuf[4]);
+               return 1;
+       }
+       /* Enter raw SPI mode */
+       bp_commbuf[0] = 0x01;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 4);
+       if (ret)
+               return ret;
+       if (memcmp(bp_commbuf, "SPI", 3)) {
+               msg_perr("Entering raw SPI mode failed!\n");
+               msg_pdbg("Got %02x%02x%02x%02x\n",
+                        bp_commbuf[0], bp_commbuf[1], bp_commbuf[2],
+                        bp_commbuf[3]);
+               return 1;
+       }
+       msg_pdbg("Raw SPI mode version %c\n", bp_commbuf[3]);
+       if (bp_commbuf[3] != '1') {
+               msg_perr("Can't handle raw SPI mode version %c!\n",
+                       bp_commbuf[3]);
+               return 1;
+       }
+
+       /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
+       bp_commbuf[0] = 0x40 | 0xb;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 1);
+       if (ret)
+               return 1;
+       if (bp_commbuf[0] != 0x01) {
+               msg_perr("Protocol error while setting power/CS/AUX!\n");
+               return 1;
+       }
+
+       /* Set SPI speed */
+       bp_commbuf[0] = 0x60 | spispeed;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 1);
+       if (ret)
+               return 1;
+       if (bp_commbuf[0] != 0x01) {
+               msg_perr("Protocol error while setting SPI speed!\n");
+               return 1;
+       }
+       
+       /* Set SPI config: output type, idle, clock edge, sample */
+       bp_commbuf[0] = 0x80 | 0xa;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 1);
+       if (ret)
+               return 1;
+       if (bp_commbuf[0] != 0x01) {
+               msg_perr("Protocol error while setting SPI config!\n");
+               return 1;
+       }
+
+       /* De-assert CS# */
+       bp_commbuf[0] = 0x03;
+       ret = buspirate_sendrecv(bp_commbuf, 1, 1);
+       if (ret)
+               return 1;
+       if (bp_commbuf[0] != 0x01) {
+               msg_perr("Protocol error while raising CS#!\n");
+               return 1;
+       }
+
+       register_spi_programmer(&spi_programmer_buspirate);
+
+       return 0;
+}
+
+static int buspirate_spi_send_command(struct flashctx *flash,
+                                     unsigned int writecnt,
+                                     unsigned int readcnt,
+                                     const unsigned char *writearr,
+                                     unsigned char *readarr)
+{
+       unsigned int i = 0;
+       int ret = 0;
+
+       if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
+               return SPI_INVALID_LENGTH;
+
+       /* 3 bytes extra for CS#, len, CS#. */
+       if (buspirate_commbuf_grow(writecnt + readcnt + 3))
+               return ERROR_OOM;
+
+       /* Assert CS# */
+       bp_commbuf[i++] = 0x02;
+
+       bp_commbuf[i++] = 0x10 | (writecnt + readcnt - 1);
+       memcpy(bp_commbuf + i, writearr, writecnt);
+       i += writecnt;
+       memset(bp_commbuf + i, 0, readcnt);
+
+       i += readcnt;
+       /* De-assert CS# */
+       bp_commbuf[i++] = 0x03;
+
+       ret = buspirate_sendrecv(bp_commbuf, i, i);
+
+       if (ret) {
+               msg_perr("Bus Pirate communication error!\n");
+               return SPI_GENERIC_ERROR;
+       }
+
+       if (bp_commbuf[0] != 0x01) {
+               msg_perr("Protocol error while lowering CS#!\n");
+               return SPI_GENERIC_ERROR;
+       }
+
+       if (bp_commbuf[1] != 0x01) {
+               msg_perr("Protocol error while reading/writing SPI!\n");
+               return SPI_GENERIC_ERROR;
+       }
+
+       if (bp_commbuf[i - 1] != 0x01) {
+               msg_perr("Protocol error while raising CS#!\n");
+               return SPI_GENERIC_ERROR;
+       }
+
+       /* Skip CS#, length, writearr. */
+       memcpy(readarr, bp_commbuf + 2 + writecnt, readcnt);
+
+       return ret;
+}
diff --git a/cbtable.c b/cbtable.c
new file mode 100644 (file)
index 0000000..4495d9d
--- /dev/null
+++ b/cbtable.c
@@ -0,0 +1,265 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2002 Steven James <pyro@linuxlabs.com>
+ * Copyright (C) 2002 Linux Networx
+ * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
+ * Copyright (C) 2006-2009 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan@coresystems.de> 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
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "programmer.h"
+#include "coreboot_tables.h"
+
+char *lb_part = NULL, *lb_vendor = NULL;
+int partvendor_from_cbtable = 0;
+
+/* Parse the [<vendor>:]<board> string specified by the user as part of
+ * -p internal:mainboard=[<vendor>:]<board> and set lb_vendor and lb_part
+ * to the extracted values.
+ * Note: strtok modifies the original string, so we work on a copy and allocate
+ * memory for lb_vendor and lb_part with strdup.
+ */
+void lb_vendor_dev_from_string(const char *boardstring)
+{
+       /* strtok may modify the original string. */
+       char *tempstr = strdup(boardstring);
+       char *tempstr2 = NULL;
+       strtok(tempstr, ":");
+       tempstr2 = strtok(NULL, ":");
+       if (tempstr2) {
+               lb_vendor = strdup(tempstr);
+               lb_part = strdup(tempstr2);
+       } else {
+               lb_vendor = NULL;
+               lb_part = strdup(tempstr);
+       }
+       free(tempstr);
+}
+
+static unsigned long compute_checksum(void *addr, unsigned long length)
+{
+       uint8_t *ptr;
+       volatile union {
+               uint8_t byte[2];
+               uint16_t word;
+       } chksum;
+       unsigned long sum;
+       unsigned long i;
+
+       /* In the most straight forward way possible,
+        * compute an ip style checksum.
+        */
+       sum = 0;
+       ptr = addr;
+       for (i = 0; i < length; i++) {
+               unsigned long value;
+               value = ptr[i];
+               if (i & 1) {
+                       value <<= 8;
+               }
+               /* Add the new value */
+               sum += value;
+               /* Wrap around the carry */
+               if (sum > 0xFFFF) {
+                       sum = (sum + (sum >> 16)) & 0xFFFF;
+               }
+       }
+       chksum.byte[0] = sum & 0xff;
+       chksum.byte[1] = (sum >> 8) & 0xff;
+
+       return (~chksum.word) & 0xFFFF;
+}
+
+#define for_each_lbrec(head, rec) \
+       for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
+               (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes))  && \
+               (rec->size >= 1) && \
+               ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
+               rec = (struct lb_record *)(((char *)rec) + rec->size))
+
+static int count_lb_records(struct lb_header *head)
+{
+       struct lb_record *rec;
+       int count;
+
+       count = 0;
+       for_each_lbrec(head, rec) {
+               count++;
+       }
+
+       return count;
+}
+
+static struct lb_header *find_lb_table(void *base, unsigned long start,
+                                      unsigned long end)
+{
+       unsigned long addr;
+
+       /* For now be stupid.... */
+       for (addr = start; addr < end; addr += 16) {
+               struct lb_header *head =
+                   (struct lb_header *)(((char *)base) + addr);
+               struct lb_record *recs =
+                   (struct lb_record *)(((char *)base) + addr + sizeof(*head));
+               if (memcmp(head->signature, "LBIO", 4) != 0)
+                       continue;
+               msg_pdbg("Found candidate at: %08lx-%08lx\n",
+                            addr, addr + head->table_bytes);
+               if (head->header_bytes != sizeof(*head)) {
+                       msg_perr("Header bytes of %d are incorrect.\n",
+                               head->header_bytes);
+                       continue;
+               }
+               if (count_lb_records(head) != head->table_entries) {
+                       msg_perr("Bad record count: %d.\n",
+                               head->table_entries);
+                       continue;
+               }
+               if (compute_checksum((uint8_t *) head, sizeof(*head)) != 0) {
+                       msg_perr("Bad header checksum.\n");
+                       continue;
+               }
+               if (compute_checksum(recs, head->table_bytes)
+                   != head->table_checksum) {
+                       msg_perr("Bad table checksum: %04x.\n",
+                               head->table_checksum);
+                       continue;
+               }
+               msg_pdbg("Found coreboot table at 0x%08lx.\n", addr);
+               return head;
+
+       };
+
+       return NULL;
+}
+
+static void find_mainboard(struct lb_record *ptr, unsigned long addr)
+{
+       struct lb_mainboard *rec;
+       int max_size;
+       char vendor[256], part[256];
+
+       rec = (struct lb_mainboard *)ptr;
+       max_size = rec->size - sizeof(*rec);
+       msg_pdbg("Vendor ID: %.*s, part ID: %.*s\n",
+              max_size - rec->vendor_idx,
+              rec->strings + rec->vendor_idx,
+              max_size - rec->part_number_idx,
+              rec->strings + rec->part_number_idx);
+       snprintf(vendor, 255, "%.*s", max_size - rec->vendor_idx,
+                rec->strings + rec->vendor_idx);
+       snprintf(part, 255, "%.*s", max_size - rec->part_number_idx,
+                rec->strings + rec->part_number_idx);
+
+       if (lb_part) {
+               msg_pdbg("Overwritten by command line, vendor ID: %s, part ID: %s.\n", lb_vendor, lb_part);
+       } else {
+               partvendor_from_cbtable = 1;
+               lb_part = strdup(part);
+               lb_vendor = strdup(vendor);
+       }
+}
+
+static struct lb_record *next_record(struct lb_record *rec)
+{
+       return (struct lb_record *)(((char *)rec) + rec->size);
+}
+
+static void search_lb_records(struct lb_record *rec, struct lb_record *last,
+                             unsigned long addr)
+{
+       struct lb_record *next;
+       int count;
+       count = 0;
+
+       for (next = next_record(rec); (rec < last) && (next <= last);
+            rec = next, addr += rec->size) {
+               next = next_record(rec);
+               count++;
+               if (rec->tag == LB_TAG_MAINBOARD) {
+                       find_mainboard(rec, addr);
+                       break;
+               }
+       }
+}
+
+#define BYTES_TO_MAP (1024*1024)
+int coreboot_init(void)
+{
+       uint8_t *table_area;
+       unsigned long addr, start;
+       struct lb_header *lb_table;
+       struct lb_record *rec, *last;
+
+#ifdef __DARWIN__
+       /* This is a hack. DirectHW fails to map physical address 0x00000000.
+        * Why?
+        */
+       start = 0x400;
+#else
+       start = 0x0;
+#endif
+       table_area = physmap_try_ro("low megabyte", start, BYTES_TO_MAP - start);
+       if (ERROR_PTR == 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 - start, BYTES_TO_MAP - start);
+       if (lb_table) {
+               struct lb_forward *forward = (struct lb_forward *)
+                       (((char *)lb_table) + lb_table->header_bytes);
+               if (forward->tag == LB_TAG_FORWARD) {
+                       start = forward->forward;
+                       start &= ~(getpagesize() - 1);
+                       physunmap(table_area, BYTES_TO_MAP);
+                       table_area = physmap_try_ro("high tables", start, BYTES_TO_MAP);
+                       if (ERROR_PTR == table_area) {
+                               msg_perr("Failed getting access to coreboot "
+                                        "high tables.\n");
+                               return -1;
+                       }
+                       lb_table = find_lb_table(table_area, 0x00000, 0x1000);
+               }
+       }
+
+       if (!lb_table) {
+               msg_pdbg("No coreboot table found.\n");
+               return -1;
+       }
+
+       addr = ((char *)lb_table) - ((char *)table_area) + start;
+       msg_pinfo("coreboot table found at 0x%lx.\n", 
+               (unsigned long)lb_table - (unsigned long)table_area + start);
+       rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes);
+       last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes);
+       msg_pdbg("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n",
+            lb_table->header_bytes, lb_table->header_checksum,
+            lb_table->table_bytes, lb_table->table_checksum,
+            lb_table->table_entries);
+       search_lb_records(rec, last, addr + lb_table->header_bytes);
+
+       return 0;
+}
diff --git a/chipdrivers.h b/chipdrivers.h
new file mode 100644 (file)
index 0000000..0c78b0d
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * 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 flashctx as first parameter.
+ */
+
+#ifndef __CHIPDRIVERS_H__
+#define __CHIPDRIVERS_H__ 1
+
+#include "flash.h"     /* for chipaddr and flashctx */
+
+/* spi.c, should probably be in spi_chip.c */
+int probe_spi_rdid(struct flashctx *flash);
+int probe_spi_rdid4(struct flashctx *flash);
+int probe_spi_rems(struct flashctx *flash);
+int probe_spi_res1(struct flashctx *flash);
+int probe_spi_res2(struct flashctx *flash);
+int spi_write_enable(struct flashctx *flash);
+int spi_write_disable(struct flashctx *flash);
+int spi_block_erase_20(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d7(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_60(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_c7(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode);
+int spi_chip_write_1(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int spi_chip_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, int unsigned len);
+uint8_t spi_read_status_register(struct flashctx *flash);
+int spi_write_status_register(struct flashctx *flash, int status);
+void spi_prettyprint_status_register_bit(uint8_t status, int bit);
+void spi_prettyprint_status_register_bp(uint8_t status, int bp);
+void spi_prettyprint_status_register_welwip(uint8_t status);
+int spi_prettyprint_status_register(struct flashctx *flash);
+int spi_disable_blockprotect(struct flashctx *flash);
+int spi_byte_program(struct flashctx *flash, unsigned int addr, uint8_t databyte);
+int spi_nbyte_program(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
+int spi_nbyte_read(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
+int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize);
+int spi_write_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize);
+int spi_aai_write(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+
+/* sfdp.c */
+int probe_spi_sfdp(struct flashctx *flash);
+
+/* opaque.c */
+int probe_opaque(struct flashctx *flash);
+int read_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int write_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+
+/* a25.c */
+int spi_prettyprint_status_register_amic_a25l05p(struct flashctx *flash);
+int spi_prettyprint_status_register_amic_a25l40p(struct flashctx *flash);
+int spi_prettyprint_status_register_amic_a25l032(struct flashctx *flash);
+int spi_prettyprint_status_register_amic_a25lq032(struct flashctx *flash);
+
+/* at25.c */
+int spi_prettyprint_status_register_at25df(struct flashctx *flash);
+int spi_prettyprint_status_register_at25df_sec(struct flashctx *flash);
+int spi_prettyprint_status_register_at25f(struct flashctx *flash);
+int spi_prettyprint_status_register_at25fs010(struct flashctx *flash);
+int spi_prettyprint_status_register_at25fs040(struct flashctx *flash);
+int spi_prettyprint_status_register_atmel_at26df081a(struct flashctx *flash);
+int spi_disable_blockprotect_at25df(struct flashctx *flash);
+int spi_disable_blockprotect_at25df_sec(struct flashctx *flash);
+int spi_disable_blockprotect_at25f(struct flashctx *flash);
+int spi_disable_blockprotect_at25fs010(struct flashctx *flash);
+int spi_disable_blockprotect_at25fs040(struct flashctx *flash);
+
+/* 82802ab.c */
+uint8_t wait_82802ab(struct flashctx *flash);
+int probe_82802ab(struct flashctx *flash);
+int erase_block_82802ab(struct flashctx *flash, unsigned int page, unsigned int pagesize);
+int write_82802ab(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+void print_status_82802ab(uint8_t status);
+int unlock_82802ab(struct flashctx *flash);
+int unlock_28f004s5(struct flashctx *flash);
+int unlock_lh28f008bjt(struct flashctx *flash);
+
+/* jedec.c */
+uint8_t oddparity(uint8_t val);
+void toggle_ready_jedec(struct flashctx *flash, chipaddr dst);
+void data_polling_jedec(struct flashctx *flash, chipaddr dst, uint8_t data);
+int write_byte_program_jedec(struct flashctx *flash, chipaddr bios, uint8_t *src,
+                            chipaddr dst);
+int probe_jedec(struct flashctx *flash);
+int write_jedec(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int write_jedec_1(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int pagesize);
+int erase_block_jedec(struct flashctx *flash, unsigned int page, unsigned int blocksize);
+int erase_chip_block_jedec(struct flashctx *flash, unsigned int page, unsigned int blocksize);
+
+/* m29f400bt.c */
+int probe_m29f400bt(struct flashctx *flash);
+int block_erase_m29f400bt(struct flashctx *flash, unsigned int start, unsigned int len);
+int block_erase_chip_m29f400bt(struct flashctx *flash, unsigned int start, unsigned int len);
+int write_m29f400bt(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+void protect_m29f400bt(struct flashctx *flash, chipaddr bios);
+
+/* pm49fl00x.c */
+int unlock_49fl00x(struct flashctx *flash);
+int lock_49fl00x(struct flashctx *flash);
+
+/* sst28sf040.c */
+int erase_chip_28sf040(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int erase_sector_28sf040(struct flashctx *flash, unsigned int address, unsigned int sector_size);
+int write_28sf040(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int unprotect_28sf040(struct flashctx *flash);
+int protect_28sf040(struct flashctx *flash);
+
+/* sst49lfxxxc.c */
+int erase_sector_49lfxxxc(struct flashctx *flash, unsigned int address, unsigned int sector_size);
+int unlock_49lfxxxc(struct flashctx *flash);
+
+/* sst_fwhub.c */
+int printlock_sst_fwhub(struct flashctx *flash);
+int unlock_sst_fwhub(struct flashctx *flash);
+
+/* w39.c */
+int printlock_w39l040(struct flashctx * flash);
+int printlock_w39v040a(struct flashctx *flash);
+int printlock_w39v040b(struct flashctx *flash);
+int printlock_w39v040c(struct flashctx *flash);
+int printlock_w39v040fa(struct flashctx *flash);
+int printlock_w39v040fb(struct flashctx *flash);
+int printlock_w39v040fc(struct flashctx *flash);
+int printlock_w39v080a(struct flashctx *flash);
+int printlock_w39v080fa(struct flashctx *flash);
+int printlock_w39v080fa_dual(struct flashctx *flash);
+int unlock_w39v040fb(struct flashctx *flash);
+int unlock_w39v080fa(struct flashctx *flash);
+int printlock_at49f(struct flashctx *flash);
+
+/* w29ee011.c */
+int probe_w29ee011(struct flashctx *flash);
+
+/* stm50flw0x0x.c */
+int erase_sector_stm50flw0x0x(struct flashctx *flash, unsigned int block, unsigned int blocksize);
+int unlock_stm50flw0x0x(struct flashctx *flash);
+
+/* en29lv640b.c */
+int probe_en29lv640b(struct flashctx *flash);
+int block_erase_en29lv640b(struct flashctx *flash, unsigned int start, unsigned int len);
+int block_erase_chip_en29lv640b(struct flashctx *flash, unsigned int start, unsigned int len);
+int write_en29lv640b(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+
+#endif /* !__CHIPDRIVERS_H__ */
diff --git a/chipset_enable.c b/chipset_enable.c
new file mode 100644 (file)
index 0000000..936d7b8
--- /dev/null
@@ -0,0 +1,1465 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2005-2009 coresystems GmbH
+ * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.de>
+ * 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
+ * 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 chipset specific flash enables.
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define NOT_DONE_YET 1
+
+#if defined(__i386__) || defined(__x86_64__)
+
+static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name)
+{
+       uint8_t tmp;
+
+       /*
+        * ROM Write enable, 0xFFFC0000-0xFFFDFFFF and
+        * 0xFFFE0000-0xFFFFFFFF ROM select enable.
+        */
+       tmp = pci_read_byte(dev, 0x47);
+       tmp |= 0x46;
+       rpci_write_byte(dev, 0x47, tmp);
+
+       return 0;
+}
+
+static int enable_flash_rdc_r8610(struct pci_dev *dev, const char *name)
+{
+       uint8_t tmp;
+
+       /* enable ROMCS for writes */
+       tmp = pci_read_byte(dev, 0x43);
+       tmp |= 0x80;
+       pci_write_byte(dev, 0x43, tmp);
+
+       /* read the bootstrapping register */
+       tmp = pci_read_byte(dev, 0x40) & 0x3;
+       switch (tmp) {
+       case 3:
+               internal_buses_supported = BUS_FWH;
+               break;
+       case 2:
+               internal_buses_supported = BUS_LPC;
+               break;
+       default:
+               internal_buses_supported = BUS_PARALLEL;
+               break;
+       }
+
+       return 0;
+}
+
+static int enable_flash_sis85c496(struct pci_dev *dev, const char *name)
+{
+       uint8_t tmp;
+
+       tmp = pci_read_byte(dev, 0xd0);
+       tmp |= 0xf8;
+       rpci_write_byte(dev, 0xd0, tmp);
+
+       return 0;
+}
+
+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. */
+       rpci_write_byte(dev, 0x40, new);
+       newer = pci_read_byte(dev, 0x40);
+       if (newer != new) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x40, new, name);
+               msg_pinfo("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)
+               msg_perr("No southbridge found for %s!\n", name);
+       if (sbdev)
+               msg_pdbg("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;
+       rpci_write_byte(sbdev, 0x45, new);
+       newer = pci_read_byte(sbdev, 0x45);
+       if (newer != new) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x45, new, name);
+               msg_pinfo("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;
+       rpci_write_byte(sbdev, 0x45, new);
+       newer = pci_read_byte(sbdev, 0x45);
+       if (newer != new) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x45, new, name);
+               msg_pinfo("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
+ *   - PDF: http://www.intel.com/design/intarch/datashts/29056201.pdf
+ *   - Order Number: 290562-001
+ */
+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. */
+
+       internal_buses_supported = BUS_PARALLEL;
+
+       old = pci_read_word(dev, xbcs);
+
+       /* Set bit 9: 1-Meg Extended BIOS Enable (PCI master accesses to
+        *            FFF00000-FFF7FFFF are forwarded to ISA).
+        *            Note: This bit is reserved on PIIX/PIIX3/MPIIX.
+        * Set bit 7: Extended BIOS Enable (PCI master accesses to
+        *            FFF80000-FFFDFFFF are forwarded to ISA).
+        * Set bit 6: Lower BIOS Enable (PCI master, or ISA master accesses to
+        *            the lower 64-Kbyte BIOS block (E0000-EFFFF) at the top
+        *            of 1 Mbyte, or the aliases at the top of 4 Gbyte
+        *            (FFFE0000-FFFEFFFF) result in the generation of BIOSCS#.
+        * Note: Accesses to FFFF0000-FFFFFFFF are always forwarded to ISA.
+        * Set bit 2: BIOSCS# Write Enable (1=enable, 0=disable).
+        */
+       if (dev->device_id == 0x122e || dev->device_id == 0x7000
+           || dev->device_id == 0x1234)
+               new = old | 0x00c4; /* PIIX/PIIX3/MPIIX: Bit 9 is reserved. */
+       else
+               new = old | 0x02c4;
+
+       if (new == old)
+               return 0;
+
+       rpci_write_word(dev, xbcs, new);
+
+       if (pci_read_word(dev, xbcs) != new) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", xbcs, new, name);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet"
+ * http://download.intel.com/design/chipsets/datashts/30701303.pdf
+ */
+static int enable_flash_ich(struct pci_dev *dev, const char *name,
+                           int bios_cntl)
+{
+       uint8_t old, new, wanted;
+
+       /*
+        * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, but
+        * just treating it as 8 bit wide seems to work fine in practice.
+        */
+       old = pci_read_byte(dev, bios_cntl);
+
+       msg_pdbg("\nBIOS Lock Enable: %sabled, ",
+                (old & (1 << 1)) ? "en" : "dis");
+       msg_pdbg("BIOS Write Enable: %sabled, ",
+                (old & (1 << 0)) ? "en" : "dis");
+       msg_pdbg("BIOS_CNTL is 0x%x\n", old);
+
+       /*
+        * Quote from the 6 Series datasheet (Document Number: 324645-004):
+        * "Bit 5: SMM BIOS Write Protect Disable (SMM_BWP)
+        * 1 = BIOS region SMM protection is enabled.
+        * The BIOS Region is not writable unless all processors are in SMM."
+        * In earlier chipsets this bit is reserved.
+        */
+       if (old & (1 << 5))
+               msg_pinfo("WARNING: BIOS region SMM protection is enabled!\n");
+
+       wanted = old | 1;
+       if (wanted == old)
+               return 0;
+
+       rpci_write_byte(dev, bios_cntl, wanted);
+
+       if ((new = pci_read_byte(dev, bios_cntl)) != wanted) {
+               msg_pinfo("WARNING: Setting 0x%x from 0x%x to 0x%x on %s "
+                         "failed. New value is 0x%x.\n",
+                         bios_cntl, old, wanted, name, new);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int enable_flash_ich_4e(struct pci_dev *dev, const char *name)
+{
+       /*
+        * Note: ICH5 has registers similar to FWH_SEL1, FWH_SEL2 and
+        * FWH_DEC_EN1, but they are called FB_SEL1, FB_SEL2, FB_DEC_EN1 and
+        * FB_DEC_EN2.
+        */
+       internal_buses_supported = BUS_FWH;
+       return enable_flash_ich(dev, name, 0x4e);
+}
+
+static int enable_flash_ich_dc(struct pci_dev *dev, const char *name)
+{
+       uint32_t fwh_conf;
+       int i, tmp;
+       char *idsel = NULL;
+       int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0;
+       int contiguous = 1;
+
+       idsel = extract_programmer_param("fwh_idsel");
+       if (idsel && strlen(idsel)) {
+               uint64_t fwh_idsel_old, fwh_idsel;
+               errno = 0;
+               /* Base 16, nothing else makes sense. */
+               fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16);
+               if (errno) {
+                       msg_perr("Error: fwh_idsel= specified, but value could "
+                                "not be converted.\n");
+                       goto idsel_garbage_out;
+               }
+               if (fwh_idsel & 0xffff000000000000ULL) {
+                       msg_perr("Error: fwh_idsel= specified, but value had "
+                                "unused bits set.\n");
+                       goto idsel_garbage_out;
+               }
+               fwh_idsel_old = pci_read_long(dev, 0xd0);
+               fwh_idsel_old <<= 16;
+               fwh_idsel_old |= pci_read_word(dev, 0xd4);
+               msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to "
+                        "0x%012" PRIx64 " for top 16 MB.", fwh_idsel_old,
+                        fwh_idsel);
+               rpci_write_long(dev, 0xd0, (fwh_idsel >> 16) & 0xffffffff);
+               rpci_write_word(dev, 0xd4, fwh_idsel & 0xffff);
+               /* FIXME: Decode settings are not changed. */
+       } else if (idsel) {
+               msg_perr("Error: fwh_idsel= specified, but no value given.\n");
+idsel_garbage_out:
+               free(idsel);
+               return ERROR_FATAL;
+       }
+       free(idsel);
+
+       /* 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--) {
+               tmp = (fwh_conf >> (i * 4)) & 0xf;
+               msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
+                        (0x1ff8 + i) * 0x80000,
+                        (0x1ff0 + i) * 0x80000,
+                        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--) {
+               tmp = (fwh_conf >> (i * 4)) & 0xf;
+               msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
+                        (0xff4 + i) * 0x100000,
+                        (0xff0 + i) * 0x100000,
+                        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--) {
+               tmp = (fwh_conf >> (i + 0x8)) & 0x1;
+               msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled",
+                        (0x1ff8 + i) * 0x80000,
+                        (0x1ff0 + i) * 0x80000,
+                        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;
+               msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled",
+                        (0xff4 + i) * 0x100000,
+                        (0xff0 + i) * 0x100000,
+                        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);
+       msg_pdbg("\nMaximum FWH chip size: 0x%x bytes", max_rom_decode.fwh);
+
+       /* If we're called by enable_flash_ich_dc_spi, it will override
+        * internal_buses_supported anyway.
+        */
+       internal_buses_supported = BUS_FWH;
+       return enable_flash_ich(dev, name, 0xdc);
+}
+
+static int enable_flash_poulsbo(struct pci_dev *dev, const char *name)
+{
+       uint16_t old, new;
+       int err;
+
+       if ((err = enable_flash_ich(dev, name, 0xd8)) != 0)
+               return err;
+
+       old = pci_read_byte(dev, 0xd9);
+       msg_pdbg("BIOS Prefetch Enable: %sabled, ",
+                (old & 1) ? "en" : "dis");
+       new = old & ~1;
+
+       if (new != old)
+               rpci_write_byte(dev, 0xd9, new);
+
+       internal_buses_supported = BUS_FWH;
+       return 0;
+}
+
+static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name)
+{
+       uint16_t old, new;
+       uint32_t tmp, bnt;
+       void *rcrb;
+       int ret;
+
+       /* Enable Flash Writes */
+       ret = enable_flash_ich(dev, name, 0xd8);
+       if (ret == ERROR_FATAL)
+               return ret;
+
+       /* Make sure BIOS prefetch mechanism is disabled */
+       old = pci_read_byte(dev, 0xd9);
+       msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis");
+       new = old & ~1;
+       if (new != old)
+               rpci_write_byte(dev, 0xd9, new);
+
+       /* Get physical address of Root Complex Register Block */
+       tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
+       msg_pdbg("\nRoot Complex Register Block address = 0x%x\n", tmp);
+
+       /* Map RCBA to virtual memory */
+       rcrb = physmap("ICH RCRB", tmp, 0x4000);
+
+       /* Test Boot BIOS Strap Status */
+       bnt = mmio_readl(rcrb + 0x3410);
+       if (bnt & 0x02) {
+               /* If strapped to LPC, no SPI initialization is required */
+               internal_buses_supported = BUS_FWH;
+               return 0;
+       }
+
+       /* This adds BUS_SPI */
+       if (ich_init_spi(dev, tmp, rcrb, 7) != 0) {
+               if (!ret)
+                       ret = ERROR_NONFATAL;
+       }
+
+       return ret;
+}
+
+static int enable_flash_vt8237s_spi(struct pci_dev *dev, const char *name)
+{
+       /* Do we really need no write enable? */
+       return via_init_spi(dev);
+}
+
+static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
+                                  enum ich_chipset ich_generation)
+{
+       int ret, ret_spi;
+       uint8_t bbs, buc;
+       uint32_t tmp, gcs;
+       void *rcrb;
+       const char *const *straps_names;
+
+       static const char *const straps_names_EP80579[] = { "SPI", "reserved", "reserved", "LPC" };
+       static const char *const straps_names_ich7_nm10[] = { "reserved", "SPI", "PCI", "LPC" };
+       static const char *const straps_names_ich8910[] = { "SPI", "SPI", "PCI", "LPC" };
+       static const char *const straps_names_pch567[] = { "LPC", "reserved", "PCI", "SPI" };
+       static const char *const straps_names_unknown[] = { "unknown", "unknown", "unknown", "unknown" };
+
+       switch (ich_generation) {
+       case CHIPSET_ICH7:
+               /* EP80579 may need further changes, but this is the least
+                * intrusive way to get correct BOOT Strap printing without
+                * changing the rest of its code path). */
+               if (strcmp(name, "EP80579") == 0)
+                       straps_names = straps_names_EP80579;
+               else
+                       straps_names = straps_names_ich7_nm10;
+               break;
+       case CHIPSET_ICH8:
+       case CHIPSET_ICH9:
+       case CHIPSET_ICH10:
+               straps_names = straps_names_ich8910;
+               break;
+       case CHIPSET_5_SERIES_IBEX_PEAK:
+       case CHIPSET_6_SERIES_COUGAR_POINT:
+       case CHIPSET_7_SERIES_PANTHER_POINT:
+               straps_names = straps_names_pch567;
+               break;
+       default:
+               msg_gerr("%s: unknown ICH generation. Please report!\n",
+                        __func__);
+               straps_names = straps_names_unknown;
+               break;
+       }
+
+       /* Enable Flash Writes */
+       ret = enable_flash_ich_dc(dev, name);
+       if (ret == ERROR_FATAL)
+               return ret;
+
+       /* Get physical address of Root Complex Register Block */
+       tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
+       msg_pdbg("Root Complex Register Block address = 0x%x\n", tmp);
+
+       /* Map RCBA to virtual memory */
+       rcrb = physmap("ICH RCRB", tmp, 0x4000);
+
+       gcs = mmio_readl(rcrb + 0x3410);
+       msg_pdbg("GCS = 0x%x: ", gcs);
+       msg_pdbg("BIOS Interface Lock-Down: %sabled, ",
+                (gcs & 0x1) ? "en" : "dis");
+       bbs = (gcs >> 10) & 0x3;
+       msg_pdbg("Boot BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]);
+
+       buc = mmio_readb(rcrb + 0x3414);
+       msg_pdbg("Top Swap : %s\n",
+                (buc & 1) ? "enabled (A16 inverted)" : "not enabled");
+
+       /* It seems the ICH7 does not support SPI and LPC chips at the same
+        * time. At least not with our current code. So we prevent searching
+        * on ICH7 when the southbridge is strapped to LPC
+        */
+       internal_buses_supported = BUS_FWH;
+       if (ich_generation == CHIPSET_ICH7) {
+               if (bbs == 0x03) {
+                       /* If strapped to LPC, no further SPI initialization is
+                        * required. */
+                       return ret;
+               } else {
+                       /* Disable LPC/FWH if strapped to PCI or SPI */
+                       internal_buses_supported = BUS_NONE;
+               }
+       }
+
+       /* This adds BUS_SPI */
+       ret_spi = ich_init_spi(dev, tmp, rcrb, ich_generation);
+       if (ret_spi == ERROR_FATAL)
+               return ret_spi;
+       
+       if (ret || ret_spi)
+               ret = ERROR_NONFATAL;
+
+       return ret;
+}
+
+static int enable_flash_ich7(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH7);
+}
+
+static int enable_flash_ich8(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH8);
+}
+
+static int enable_flash_ich9(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH9);
+}
+
+static int enable_flash_ich10(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH10);
+}
+
+/* Ibex Peak aka. 5 series & 3400 series */
+static int enable_flash_pch5(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_5_SERIES_IBEX_PEAK);
+}
+
+/* Cougar Point aka. 6 series & c200 series */
+static int enable_flash_pch6(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_6_SERIES_COUGAR_POINT);
+}
+
+/* Panther Point aka. 7 series */
+static int enable_flash_pch7(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_7_SERIES_PANTHER_POINT);
+}
+
+/* Lynx Point aka. 8 series */
+static int enable_flash_pch8(struct pci_dev *dev, const char *name)
+{
+       return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT);
+}
+
+static int via_no_byte_merge(struct pci_dev *dev, const char *name)
+{
+       uint8_t val;
+
+       val = pci_read_byte(dev, 0x71);
+       if (val & 0x40) {
+               msg_pdbg("Disabling byte merging\n");
+               val &= ~0x40;
+               rpci_write_byte(dev, 0x71, val);
+       }
+       return NOT_DONE_YET;    /* need to find south bridge, too */
+}
+
+static int enable_flash_vt823x(struct pci_dev *dev, const char *name)
+{
+       uint8_t val;
+
+       /* Enable ROM decode range (1MB) FFC00000 - FFFFFFFF. */
+       rpci_write_byte(dev, 0x41, 0x7f);
+
+       /* ROM write enable */
+       val = pci_read_byte(dev, 0x40);
+       val |= 0x10;
+       rpci_write_byte(dev, 0x40, val);
+
+       if (pci_read_byte(dev, 0x40) != val) {
+               msg_pinfo("\nWARNING: Failed to enable flash write on \"%s\"\n",
+                         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;
+               rpci_write_byte(dev, 0x59, val);
+       }
+
+       return 0;
+}
+
+static int enable_flash_cs5530(struct pci_dev *dev, const char *name)
+{
+       uint8_t reg8;
+
+#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)
+
+       internal_buses_supported = BUS_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);
+       reg8 |= LOWER_ROM_ADDRESS_RANGE;
+       reg8 |= UPPER_ROM_ADDRESS_RANGE;
+       reg8 |= ROM_WRITE_ENABLE;
+       rpci_write_byte(dev, ROM_AT_LOGIC_CONTROL_REG, reg8);
+
+       /* Set positive decode on ROM. */
+       reg8 = pci_read_byte(dev, DECODE_CONTROL_REG2);
+       reg8 |= BIOS_ROM_POSITIVE_DECODE;
+       rpci_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;
+}
+
+/*
+ * Geode systems write protect the BIOS via RCONFs (cache settings similar
+ * to MTRRs). To unlock, change MSR 0x1808 top byte to 0x22. 
+ *
+ * Geode systems also write protect the NOR flash chip itself via MSR_NORF_CTL.
+ * To enable write to NOR Boot flash for the benefit of systems that have such
+ * a setup, raise MSR 0x51400018 WE_CS3 (write enable Boot Flash Chip Select).
+ */
+static int enable_flash_cs5536(struct pci_dev *dev, const char *name)
+{
+#define MSR_RCONF_DEFAULT      0x1808
+#define MSR_NORF_CTL           0x51400018
+
+       msr_t msr;
+
+       /* Geode only has a single core */
+       if (setup_cpu_msr(0))
+               return -1;
+
+       msr = rdmsr(MSR_RCONF_DEFAULT);
+       if ((msr.hi >> 24) != 0x22) {
+               msr.hi &= 0xfbffffff;
+               wrmsr(MSR_RCONF_DEFAULT, msr);
+       }
+
+       msr = rdmsr(MSR_NORF_CTL);
+       /* Raise WE_CS3 bit. */
+       msr.lo |= 0x08;
+       wrmsr(MSR_NORF_CTL, msr);
+
+       cleanup_cpu_msr();
+
+#undef MSR_RCONF_DEFAULT
+#undef MSR_NORF_CTL
+       return 0;
+}
+
+static int enable_flash_sc1100(struct pci_dev *dev, const char *name)
+{
+       uint8_t new;
+
+       rpci_write_byte(dev, 0x52, 0xee);
+
+       new = pci_read_byte(dev, 0x52);
+
+       if (new != 0xee) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x52, new, name);
+               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)
+{
+       uint8_t old, new;
+
+       /* Enable decoding at 0xffb00000 to 0xffffffff. */
+       old = pci_read_byte(dev, 0x43);
+       new = old | 0xC0;
+       if (new != old) {
+               rpci_write_byte(dev, 0x43, new);
+               if (pci_read_byte(dev, 0x43) != new) {
+                       msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                                 "(WARNING ONLY).\n", 0x43, new, name);
+               }
+       }
+
+       /* Enable 'ROM write' bit. */
+       old = pci_read_byte(dev, 0x40);
+       new = old | 0x01;
+       if (new == old)
+               return 0;
+       rpci_write_byte(dev, 0x40, new);
+
+       if (pci_read_byte(dev, 0x40) != new) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x40, new, name);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int enable_flash_sb600(struct pci_dev *dev, const char *name)
+{
+       uint32_t prot;
+       uint8_t reg;
+       int ret;
+
+       /* Clear ROM protect 0-3. */
+       for (reg = 0x50; reg < 0x60; reg += 4) {
+               prot = pci_read_long(dev, reg);
+               /* No protection flags for this region?*/
+               if ((prot & 0x3) == 0)
+                       continue;
+               msg_pinfo("SB600 %s%sprotected from 0x%08x to 0x%08x\n",
+                         (prot & 0x1) ? "write " : "",
+                         (prot & 0x2) ? "read " : "",
+                         (prot & 0xfffff800),
+                         (prot & 0xfffff800) + (((prot & 0x7fc) << 8) | 0x3ff));
+               prot &= 0xfffffffc;
+               rpci_write_byte(dev, reg, prot);
+               prot = pci_read_long(dev, reg);
+               if (prot & 0x3)
+                       msg_perr("SB600 %s%sunprotect failed from 0x%08x to 0x%08x\n",
+                                (prot & 0x1) ? "write " : "",
+                                (prot & 0x2) ? "read " : "",
+                                (prot & 0xfffff800),
+                                (prot & 0xfffff800) + (((prot & 0x7fc) << 8) | 0x3ff));
+       }
+
+       internal_buses_supported = BUS_LPC | BUS_FWH;
+
+       ret = sb600_probe_spi(dev);
+
+       /* Read ROM strap override register. */
+       OUTB(0x8f, 0xcd6);
+       reg = INB(0xcd7);
+       reg &= 0x0e;
+       msg_pdbg("ROM strap override is %sactive", (reg & 0x02) ? "" : "not ");
+       if (reg & 0x02) {
+               switch ((reg & 0x0c) >> 2) {
+               case 0x00:
+                       msg_pdbg(": LPC");
+                       break;
+               case 0x01:
+                       msg_pdbg(": PCI");
+                       break;
+               case 0x02:
+                       msg_pdbg(": FWH");
+                       break;
+               case 0x03:
+                       msg_pdbg(": SPI");
+                       break;
+               }
+       }
+       msg_pdbg("\n");
+
+       /* Force enable SPI ROM in SB600 PM register.
+        * If we enable SPI ROM here, we have to disable it after we leave.
+        * But how can we know which ROM we are going to handle? So we have
+        * to trade off. We only access LPC ROM if we boot via LPC ROM. And
+        * only SPI ROM if we boot via SPI ROM. If you want to access SPI on
+        * boards with LPC straps, you have to use the code below.
+        */
+       /*
+       OUTB(0x8f, 0xcd6);
+       OUTB(0x0e, 0xcd7);
+       */
+
+       return ret;
+}
+
+static int enable_flash_nvidia_nforce2(struct pci_dev *dev, const char *name)
+{
+       uint8_t tmp;
+
+       rpci_write_byte(dev, 0x92, 0);
+
+       tmp = pci_read_byte(dev, 0x6d);
+       tmp |= 0x01;
+       rpci_write_byte(dev, 0x6d, tmp);
+
+       return 0;
+}
+
+static int enable_flash_ck804(struct pci_dev *dev, const char *name)
+{
+       uint8_t old, new;
+
+       pci_write_byte(dev, 0x92, 0x00);
+       if (pci_read_byte(dev, 0x92) != 0x00) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x92, 0x00, name);
+       }
+
+       old = pci_read_byte(dev, 0x88);
+       new = old | 0xc0;
+       if (new != old) {
+               rpci_write_byte(dev, 0x88, new);
+               if (pci_read_byte(dev, 0x88) != new) {
+                       msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                                 "(WARNING ONLY).\n", 0x88, new, name);
+               }
+       }
+
+       old = pci_read_byte(dev, 0x6d);
+       new = old | 0x01;
+       if (new == old)
+               return 0;
+       rpci_write_byte(dev, 0x6d, new);
+
+       if (pci_read_byte(dev, 0x6d) != new) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x6d, new, name);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int enable_flash_osb4(struct pci_dev *dev, const char *name)
+{
+       uint8_t tmp;
+
+       internal_buses_supported = BUS_PARALLEL;
+
+       tmp = INB(0xc06);
+       tmp |= 0x1;
+       OUTB(tmp, 0xc06);
+
+       tmp = INB(0xc6f);
+       tmp |= 0x40;
+       OUTB(tmp, 0xc6f);
+
+       return 0;
+}
+
+/* ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) */
+static int enable_flash_sb400(struct pci_dev *dev, const char *name)
+{
+       uint8_t tmp;
+       struct pci_dev *smbusdev;
+
+       /* Look for the SMBus device. */
+       smbusdev = pci_dev_find(0x1002, 0x4372);
+
+       if (!smbusdev) {
+               msg_perr("ERROR: SMBus device not found. Aborting.\n");
+               return ERROR_FATAL;
+       }
+
+       /* Enable some SMBus stuff. */
+       tmp = pci_read_byte(smbusdev, 0x79);
+       tmp |= 0x01;
+       rpci_write_byte(smbusdev, 0x79, tmp);
+
+       /* Change southbridge. */
+       tmp = pci_read_byte(dev, 0x48);
+       tmp |= 0x21;
+       rpci_write_byte(dev, 0x48, tmp);
+
+       /* Now become a bit silly. */
+       tmp = INB(0xc6f);
+       OUTB(tmp, 0xeb);
+       OUTB(tmp, 0xeb);
+       tmp |= 0x40;
+       OUTB(tmp, 0xc6f);
+       OUTB(tmp, 0xeb);
+       OUTB(tmp, 0xeb);
+
+       return 0;
+}
+
+static int enable_flash_mcp55(struct pci_dev *dev, const char *name)
+{
+       uint8_t old, new, val;
+       uint16_t wordval;
+
+       /* Set the 0-16 MB enable bits. */
+       val = pci_read_byte(dev, 0x88);
+       val |= 0xff;            /* 256K */
+       rpci_write_byte(dev, 0x88, val);
+       val = pci_read_byte(dev, 0x8c);
+       val |= 0xff;            /* 1M */
+       rpci_write_byte(dev, 0x8c, val);
+       wordval = pci_read_word(dev, 0x90);
+       wordval |= 0x7fff;      /* 16M */
+       rpci_write_word(dev, 0x90, wordval);
+
+       old = pci_read_byte(dev, 0x6d);
+       new = old | 0x01;
+       if (new == old)
+               return 0;
+       rpci_write_byte(dev, 0x6d, new);
+
+       if (pci_read_byte(dev, 0x6d) != new) {
+               msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
+                         "(WARNING ONLY).\n", 0x6d, new, name);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * The MCP6x/MCP7x code is based on cleanroom reverse engineering.
+ * It is assumed that LPC chips need the MCP55 code and SPI chips need the
+ * code provided in enable_flash_mcp6x_7x_common.
+ */
+static int enable_flash_mcp6x_7x(struct pci_dev *dev, const char *name)
+{
+       int ret = 0, want_spi = 0;
+       uint8_t val;
+
+       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:
+               ret = enable_flash_mcp55(dev, name);
+               internal_buses_supported = BUS_LPC;
+               msg_pdbg("Flash bus type is LPC\n");
+               break;
+       case 0x2:
+               want_spi = 1;
+               /* SPI is added in mcp6x_spi_init if it works.
+                * Do we really want to disable LPC in this case?
+                */
+               internal_buses_supported = BUS_NONE;
+               msg_pdbg("Flash bus type is SPI\n");
+               msg_pinfo("SPI on this chipset is WIP. Please report any "
+                         "success or failure by mailing us the verbose "
+                         "output to flashrom@flashrom.org, thanks!\n");
+               break;
+       default:
+               /* Should not happen. */
+               internal_buses_supported = BUS_NONE;
+               msg_pdbg("Flash bus type is unknown (none)\n");
+               msg_pinfo("Something went wrong with bus type detection.\n");
+               goto out_msg;
+               break;
+       }
+
+       /* Force enable SPI and disable LPC? Not a good idea. */
+#if 0
+       val |= (1 << 6);
+       val &= ~(1 << 5);
+       rpci_write_byte(dev, 0x8a, val);
+#endif
+
+       if (mcp6x_spi_init(want_spi))
+               ret = 1;
+
+out_msg:
+       msg_pinfo("Please send the output of \"flashrom -V\" to "
+                 "flashrom@flashrom.org with\n"
+                 "your board name: flashrom -V as the subject to help us "
+                 "finish support for your\n"
+                 "chipset. Thanks.\n");
+
+       return ret;
+}
+
+static int enable_flash_ht1000(struct pci_dev *dev, const char *name)
+{
+       uint8_t val;
+
+       /* Set the 4MB enable bit. */
+       val = pci_read_byte(dev, 0x41);
+       val |= 0x0e;
+       rpci_write_byte(dev, 0x41, val);
+
+       val = pci_read_byte(dev, 0x43);
+       val |= (1 << 4);
+       rpci_write_byte(dev, 0x43, val);
+
+       return 0;
+}
+
+/*
+ * Usually on the x86 architectures (and on other PC-like platforms like some
+ * Alphas or Itanium) the system flash is mapped right below 4G. On the AMD
+ * Elan SC520 only a small piece of the system flash is mapped there, but the
+ * complete flash is mapped somewhere below 1G. The position can be determined
+ * by the BOOTCS PAR register.
+ */
+static int get_flashbase_sc520(struct pci_dev *dev, const char *name)
+{
+       int i, bootcs_found = 0;
+       uint32_t parx = 0;
+       void *mmcr;
+
+       /* 1. Map MMCR */
+       mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize());
+
+       /* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for
+        *    BOOTCS region (PARx[31:29] = 100b)e
+        */
+       for (i = 0x88; i <= 0xc4; i += 4) {
+               parx = mmio_readl(mmcr + i);
+               if ((parx >> 29) == 4) {
+                       bootcs_found = 1;
+                       break; /* BOOTCS found */
+               }
+       }
+
+       /* 3. PARx[25] = 1b --> flashbase[29:16] = PARx[13:0]
+        *    PARx[25] = 0b --> flashbase[29:12] = PARx[17:0]
+        */
+       if (bootcs_found) {
+               if (parx & (1 << 25)) {
+                       parx &= (1 << 14) - 1; /* Mask [13:0] */
+                       flashbase = parx << 16;
+               } else {
+                       parx &= (1 << 18) - 1; /* Mask [17:0] */
+                       flashbase = parx << 12;
+               }
+       } else {
+               msg_pinfo("AMD Elan SC520 detected, but no BOOTCS. "
+                         "Assuming flash at 4G.\n");
+       }
+
+       /* 4. Clean up */
+       physunmap(mmcr, getpagesize());
+       return 0;
+}
+
+#endif
+
+/* Please keep this list numerically sorted by vendor/device ID. */
+const struct penable chipset_enables[] = {
+#if defined(__i386__) || defined(__x86_64__)
+       {0x1002, 0x4377, OK, "ATI", "SB400",            enable_flash_sb400},
+       {0x1002, 0x438d, OK, "AMD", "SB600",            enable_flash_sb600},
+       {0x1002, 0x439d, OK, "AMD", "SB7x0/SB8x0/SB9x0", enable_flash_sb600},
+       {0x100b, 0x0510, NT, "AMD", "SC1100",           enable_flash_sc1100},
+       {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},
+       {0x1022, 0x7440, OK, "AMD", "AMD-768",          enable_flash_amd8111},
+       {0x1022, 0x7468, OK, "AMD", "AMD8111",          enable_flash_amd8111},
+       {0x1022, 0x780e, OK, "AMD", "Hudson",           enable_flash_sb600},
+       {0x1039, 0x0406, NT, "SiS", "501/5101/5501",    enable_flash_sis501},
+       {0x1039, 0x0496, NT, "SiS", "85C496+497",       enable_flash_sis85c496},
+       {0x1039, 0x0530, OK, "SiS", "530",              enable_flash_sis530},
+       {0x1039, 0x0540, NT, "SiS", "540",              enable_flash_sis540},
+       {0x1039, 0x0620, NT, "SiS", "620",              enable_flash_sis530},
+       {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, OK, "SiS", "645DX",            enable_flash_sis540},
+       {0x1039, 0x0648, NT, "SiS", "648",              enable_flash_sis540},
+       {0x1039, 0x0650, NT, "SiS", "650",              enable_flash_sis540},
+       {0x1039, 0x0651, OK, "SiS", "651",              enable_flash_sis540},
+       {0x1039, 0x0655, NT, "SiS", "655",              enable_flash_sis540},
+       {0x1039, 0x0661, OK, "SiS", "661",              enable_flash_sis540},
+       {0x1039, 0x0730, OK, "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, 0x0741, OK, "SiS", "741",              enable_flash_sis540},
+       {0x1039, 0x0745, OK, "SiS", "745",              enable_flash_sis540},
+       {0x1039, 0x0746, NT, "SiS", "746",              enable_flash_sis540},
+       {0x1039, 0x0748, NT, "SiS", "748",              enable_flash_sis540},
+       {0x1039, 0x0755, OK, "SiS", "755",              enable_flash_sis540},
+       {0x1039, 0x5511, NT, "SiS", "5511",             enable_flash_sis5511},
+       {0x1039, 0x5571, NT, "SiS", "5571",             enable_flash_sis530},
+       {0x1039, 0x5591, NT, "SiS", "5591/5592",        enable_flash_sis530},
+       {0x1039, 0x5596, NT, "SiS", "5596",             enable_flash_sis5511},
+       {0x1039, 0x5597, NT, "SiS", "5597/5598/5581/5120", enable_flash_sis530},
+       {0x1039, 0x5600, NT, "SiS", "600",              enable_flash_sis530},
+       {0x1078, 0x0100, OK, "AMD", "CS5530(A)",        enable_flash_cs5530},
+       {0x10b9, 0x1533, OK, "ALi", "M1533",            enable_flash_ali_m1533},
+       {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},
+       {0x10de, 0x00e0, OK, "NVIDIA", "NForce3",       enable_flash_nvidia_nforce2},
+       /* Slave, should not be here, to fix known bug for A01. */
+       {0x10de, 0x00d3, OK, "NVIDIA", "CK804",         enable_flash_ck804},
+       {0x10de, 0x0260, OK, "NVIDIA", "MCP51",         enable_flash_ck804},
+       {0x10de, 0x0261, NT, "NVIDIA", "MCP51",         enable_flash_ck804},
+       {0x10de, 0x0262, NT, "NVIDIA", "MCP51",         enable_flash_ck804},
+       {0x10de, 0x0263, NT, "NVIDIA", "MCP51",         enable_flash_ck804},
+       {0x10de, 0x0360, OK, "NVIDIA", "MCP55",         enable_flash_mcp55}, /* M57SLI*/
+       /* 10de:0361 is present in Tyan S2915 OEM systems, but not connected to
+        * the flash chip. Instead, 10de:0364 is connected to the flash chip.
+        * Until we have PCI device class matching or some fallback mechanism,
+        * this is needed to get flashrom working on Tyan S2915 and maybe other
+        * dual-MCP55 boards.
+        */
+#if 0
+       {0x10de, 0x0361, NT, "NVIDIA", "MCP55",         enable_flash_mcp55}, /* LPC */
+#endif
+       {0x10de, 0x0362, OK, "NVIDIA", "MCP55",         enable_flash_mcp55}, /* LPC */
+       {0x10de, 0x0363, OK, "NVIDIA", "MCP55",         enable_flash_mcp55}, /* LPC */
+       {0x10de, 0x0364, OK, "NVIDIA", "MCP55",         enable_flash_mcp55}, /* LPC */
+       {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, 0x03e0, OK, "NVIDIA", "MCP61",         enable_flash_mcp6x_7x},
+       {0x10de, 0x03e1, OK, "NVIDIA", "MCP61",         enable_flash_mcp6x_7x},
+       {0x10de, 0x03e2, NT, "NVIDIA", "MCP61",         enable_flash_mcp6x_7x},
+       {0x10de, 0x03e3, NT, "NVIDIA", "MCP61",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0440, NT, "NVIDIA", "MCP65",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0441, NT, "NVIDIA", "MCP65",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0442, NT, "NVIDIA", "MCP65",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0443, NT, "NVIDIA", "MCP65",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0548, OK, "NVIDIA", "MCP67",         enable_flash_mcp6x_7x},
+       {0x10de, 0x075c, NT, "NVIDIA", "MCP78S",        enable_flash_mcp6x_7x},
+       {0x10de, 0x075d, OK, "NVIDIA", "MCP78S",        enable_flash_mcp6x_7x},
+       {0x10de, 0x07d7, OK, "NVIDIA", "MCP73",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0aac, OK, "NVIDIA", "MCP79",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0aad, NT, "NVIDIA", "MCP79",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0aae, NT, "NVIDIA", "MCP79",         enable_flash_mcp6x_7x},
+       {0x10de, 0x0aaf, NT, "NVIDIA", "MCP79",         enable_flash_mcp6x_7x},
+       /* VIA northbridges */
+       {0x1106, 0x0585, NT, "VIA", "VT82C585VPX",      via_no_byte_merge},
+       {0x1106, 0x0595, NT, "VIA", "VT82C595",         via_no_byte_merge},
+       {0x1106, 0x0597, NT, "VIA", "VT82C597",         via_no_byte_merge},
+       {0x1106, 0x0601, NT, "VIA", "VT8601/VT8601A",   via_no_byte_merge},
+       {0x1106, 0x0691, OK, "VIA", "VT82C69x",         via_no_byte_merge},
+       {0x1106, 0x8601, NT, "VIA", "VT8601T",          via_no_byte_merge},
+       /* VIA southbridges */
+       {0x1106, 0x0586, OK, "VIA", "VT82C586A/B",      enable_flash_amd8111},
+       {0x1106, 0x0596, OK, "VIA", "VT82C596",         enable_flash_amd8111},
+       {0x1106, 0x0686, OK, "VIA", "VT82C686A/B",      enable_flash_amd8111},
+       {0x1106, 0x3074, OK, "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, 0x8231, NT, "VIA", "VT8231",           enable_flash_vt823x},
+       {0x1106, 0x8324, OK, "VIA", "CX700",            enable_flash_vt823x},
+       {0x1106, 0x8353, OK, "VIA", "VX800/VX820",      enable_flash_vt8237s_spi},
+       {0x1106, 0x8409, OK, "VIA", "VX855/VX875",      enable_flash_vt823x},
+       {0x1166, 0x0200, OK, "Broadcom", "OSB4",        enable_flash_osb4},
+       {0x1166, 0x0205, OK, "Broadcom", "HT-1000",     enable_flash_ht1000},
+       {0x17f3, 0x6030, OK, "RDC", "R8610/R3210",      enable_flash_rdc_r8610},
+       {0x8086, 0x122e, OK, "Intel", "PIIX",           enable_flash_piix4},
+       {0x8086, 0x1234, NT, "Intel", "MPIIX",          enable_flash_piix4},
+       {0x8086, 0x1c44, OK, "Intel", "Z68",            enable_flash_pch6},
+       {0x8086, 0x1c46, OK, "Intel", "P67",            enable_flash_pch6},
+       {0x8086, 0x1c47, NT, "Intel", "UM67",           enable_flash_pch6},
+       {0x8086, 0x1c49, NT, "Intel", "HM65",           enable_flash_pch6},
+       {0x8086, 0x1c4a, OK, "Intel", "H67",            enable_flash_pch6},
+       {0x8086, 0x1c4b, NT, "Intel", "HM67",           enable_flash_pch6},
+       {0x8086, 0x1c4c, NT, "Intel", "Q65",            enable_flash_pch6},
+       {0x8086, 0x1c4d, NT, "Intel", "QS67",           enable_flash_pch6},
+       {0x8086, 0x1c4e, NT, "Intel", "Q67",            enable_flash_pch6},
+       {0x8086, 0x1c4f, NT, "Intel", "QM67",           enable_flash_pch6},
+       {0x8086, 0x1c50, NT, "Intel", "B65",            enable_flash_pch6},
+       {0x8086, 0x1c52, NT, "Intel", "C202",           enable_flash_pch6},
+       {0x8086, 0x1c54, NT, "Intel", "C204",           enable_flash_pch6},
+       {0x8086, 0x1c56, NT, "Intel", "C206",           enable_flash_pch6},
+       {0x8086, 0x1c5c, OK, "Intel", "H61",            enable_flash_pch6},
+       {0x8086, 0x1d40, OK, "Intel", "X79",            enable_flash_pch6},
+       {0x8086, 0x1d41, NT, "Intel", "X79",            enable_flash_pch6},
+       {0x8086, 0x1e44, NT, "Intel", "Z77",            enable_flash_pch7},
+       {0x8086, 0x1e46, NT, "Intel", "Z75",            enable_flash_pch7},
+       {0x8086, 0x1e49, NT, "Intel", "B75",            enable_flash_pch7},
+       {0x8086, 0x1e4a, NT, "Intel", "H77",            enable_flash_pch7},
+       {0x8086, 0x1e55, OK, "Intel", "QM77",           enable_flash_pch7},
+       {0x8086, 0x1e57, NT, "Intel", "HM77",           enable_flash_pch7},
+       {0x8086, 0x1e58, NT, "Intel", "UM77",           enable_flash_pch7},
+       {0x8086, 0x1e59, NT, "Intel", "HM76",           enable_flash_pch7},
+       {0x8086, 0x1e5d, NT, "Intel", "HM75",           enable_flash_pch7},
+       {0x8086, 0x1e5e, NT, "Intel", "HM70",           enable_flash_pch7},
+       {0x8086, 0x2310, NT, "Intel", "DH89xxCC",       enable_flash_pch7},
+       {0x8086, 0x2410, OK, "Intel", "ICH",            enable_flash_ich_4e},
+       {0x8086, 0x2420, OK, "Intel", "ICH0",           enable_flash_ich_4e},
+       {0x8086, 0x2440, OK, "Intel", "ICH2",           enable_flash_ich_4e},
+       {0x8086, 0x244c, OK, "Intel", "ICH2-M",         enable_flash_ich_4e},
+       {0x8086, 0x2450, NT, "Intel", "C-ICH",          enable_flash_ich_4e},
+       {0x8086, 0x2480, OK, "Intel", "ICH3-S",         enable_flash_ich_4e},
+       {0x8086, 0x248c, OK, "Intel", "ICH3-M",         enable_flash_ich_4e},
+       {0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L",    enable_flash_ich_4e},
+       {0x8086, 0x24cc, OK, "Intel", "ICH4-M",         enable_flash_ich_4e},
+       {0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R",     enable_flash_ich_4e},
+       {0x8086, 0x25a1, OK, "Intel", "6300ESB",        enable_flash_ich_4e},
+       {0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R",     enable_flash_ich_dc},
+       {0x8086, 0x2641, OK, "Intel", "ICH6-M",         enable_flash_ich_dc},
+       {0x8086, 0x2642, NT, "Intel", "ICH6W/ICH6RW",   enable_flash_ich_dc},
+       {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc},
+       {0x8086, 0x27b0, OK, "Intel", "ICH7DH",         enable_flash_ich7},
+       {0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R",     enable_flash_ich7},
+       {0x8086, 0x27b9, OK, "Intel", "ICH7M",          enable_flash_ich7},
+       {0x8086, 0x27bc, OK, "Intel", "NM10",           enable_flash_ich7},
+       {0x8086, 0x27bd, OK, "Intel", "ICH7MDH",        enable_flash_ich7},
+       {0x8086, 0x2810, OK, "Intel", "ICH8/ICH8R",     enable_flash_ich8},
+       {0x8086, 0x2811, OK, "Intel", "ICH8M-E",        enable_flash_ich8},
+       {0x8086, 0x2812, OK, "Intel", "ICH8DH",         enable_flash_ich8},
+       {0x8086, 0x2814, OK, "Intel", "ICH8DO",         enable_flash_ich8},
+       {0x8086, 0x2815, OK, "Intel", "ICH8M",          enable_flash_ich8},
+       {0x8086, 0x2910, OK, "Intel", "ICH9 Engineering Sample", enable_flash_ich9},
+       {0x8086, 0x2912, OK, "Intel", "ICH9DH",         enable_flash_ich9},
+       {0x8086, 0x2914, OK, "Intel", "ICH9DO",         enable_flash_ich9},
+       {0x8086, 0x2916, OK, "Intel", "ICH9R",          enable_flash_ich9},
+       {0x8086, 0x2917, OK, "Intel", "ICH9M-E",        enable_flash_ich9},
+       {0x8086, 0x2918, OK, "Intel", "ICH9",           enable_flash_ich9},
+       {0x8086, 0x2919, OK, "Intel", "ICH9M",          enable_flash_ich9},
+       {0x8086, 0x3a10, NT, "Intel", "ICH10R Engineering Sample", enable_flash_ich10},
+       {0x8086, 0x3a14, OK, "Intel", "ICH10DO",        enable_flash_ich10},
+       {0x8086, 0x3a16, OK, "Intel", "ICH10R",         enable_flash_ich10},
+       {0x8086, 0x3a18, OK, "Intel", "ICH10",          enable_flash_ich10},
+       {0x8086, 0x3a1a, OK, "Intel", "ICH10D",         enable_flash_ich10},
+       {0x8086, 0x3a1e, NT, "Intel", "ICH10 Engineering Sample", enable_flash_ich10},
+       {0x8086, 0x3b00, NT, "Intel", "3400 Desktop",   enable_flash_pch5},
+       {0x8086, 0x3b01, NT, "Intel", "3400 Mobile",    enable_flash_pch5},
+       {0x8086, 0x3b02, NT, "Intel", "P55",            enable_flash_pch5},
+       {0x8086, 0x3b03, NT, "Intel", "PM55",           enable_flash_pch5},
+       {0x8086, 0x3b06, OK, "Intel", "H55",            enable_flash_pch5},
+       {0x8086, 0x3b07, OK, "Intel", "QM57",           enable_flash_pch5},
+       {0x8086, 0x3b08, NT, "Intel", "H57",            enable_flash_pch5},
+       {0x8086, 0x3b09, NT, "Intel", "HM55",           enable_flash_pch5},
+       {0x8086, 0x3b0a, NT, "Intel", "Q57",            enable_flash_pch5},
+       {0x8086, 0x3b0b, NT, "Intel", "HM57",           enable_flash_pch5},
+       {0x8086, 0x3b0d, NT, "Intel", "3400 Mobile SFF", enable_flash_pch5},
+       {0x8086, 0x3b0e, NT, "Intel", "B55",            enable_flash_pch5},
+       {0x8086, 0x3b0f, OK, "Intel", "QS57",           enable_flash_pch5},
+       {0x8086, 0x3b12, NT, "Intel", "3400",           enable_flash_pch5},
+       {0x8086, 0x3b14, OK, "Intel", "3420",           enable_flash_pch5},
+       {0x8086, 0x3b16, NT, "Intel", "3450",           enable_flash_pch5},
+       {0x8086, 0x3b1e, NT, "Intel", "B55",            enable_flash_pch5},
+       {0x8086, 0x5031, OK, "Intel", "EP80579",        enable_flash_ich7},
+       {0x8086, 0x7000, OK, "Intel", "PIIX3",          enable_flash_piix4},
+       {0x8086, 0x7110, OK, "Intel", "PIIX4/4E/4M",    enable_flash_piix4},
+       {0x8086, 0x7198, OK, "Intel", "440MX",          enable_flash_piix4},
+       {0x8086, 0x8119, OK, "Intel", "SCH Poulsbo",    enable_flash_poulsbo},
+       {0x8086, 0x8186, OK, "Intel", "Atom E6xx(T)/Tunnel Creek", enable_flash_tunnelcreek},
+       {0x8086, 0x8c40, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c41, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c42, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c43, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c44, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c45, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c46, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c47, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c48, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c49, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c4a, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c4b, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c4c, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c4d, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c4e, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c4f, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c50, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c51, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c52, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c53, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c54, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c55, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c56, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c57, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c58, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c59, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c5a, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c5b, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c5c, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c5d, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c5e, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+       {0x8086, 0x8c5f, NT, "Intel", "Lynx Point",     enable_flash_pch8},
+#endif
+       {},
+};
+
+int chipset_flash_enable(void)
+{
+       struct pci_dev *dev = NULL;
+       int ret = -2;           /* Nothing! */
+       int i;
+
+       /* Now let's try to find the chipset we have... */
+       for (i = 0; chipset_enables[i].vendor_name != NULL; i++) {
+               dev = pci_dev_find(chipset_enables[i].vendor_id,
+                                  chipset_enables[i].device_id);
+               if (!dev)
+                       continue;
+               if (ret != -2) {
+                       msg_pinfo("WARNING: unexpected second chipset match: "
+                                   "\"%s %s\"\n"
+                                 "ignoring, please report lspci and board URL "
+                                   "to flashrom@flashrom.org\n"
+                                 "with \'CHIPSET: your board name\' in the "
+                                   "subject line.\n",
+                               chipset_enables[i].vendor_name,
+                                       chipset_enables[i].device_name);
+                       continue;
+               }
+               msg_pinfo("Found chipset \"%s %s\"",
+                         chipset_enables[i].vendor_name,
+                         chipset_enables[i].device_name);
+               msg_pdbg(" with PCI ID %04x:%04x",
+                        chipset_enables[i].vendor_id,
+                        chipset_enables[i].device_id);
+               msg_pinfo(". ");
+
+               if (chipset_enables[i].status == NT) {
+                       msg_pinfo("\nThis chipset is marked as untested. If "
+                                 "you are using an up-to-date version\nof "
+                                 "flashrom *and* were (not) able to "
+                                 "successfully update your firmware with it,\n"
+                                 "then please email a report to "
+                                 "flashrom@flashrom.org including a verbose "
+                                 "(-V) log.\nThank you!\n");
+               }
+               msg_pinfo("Enabling flash write... ");
+               ret = chipset_enables[i].doit(dev,
+                                             chipset_enables[i].device_name);
+               if (ret == NOT_DONE_YET) {
+                       ret = -2;
+                       msg_pinfo("OK - searching further chips.\n");
+               } else if (ret < 0)
+                       msg_pinfo("FAILED!\n");
+               else if (ret == 0)
+                       msg_pinfo("OK.\n");
+               else if (ret == ERROR_NONFATAL)
+                       msg_pinfo("PROBLEMS, continuing anyway\n");
+               if (ret == ERROR_FATAL) {
+                       msg_perr("FATAL ERROR!\n");
+                       return ret;
+               }
+       }
+
+       return ret;
+}
diff --git a/cli_classic.c b/cli_classic.c
new file mode 100644 (file)
index 0000000..cf3874c
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
+ * 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 <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include "flash.h"
+#include "flashchips.h"
+#include "programmer.h"
+
+static void cli_classic_usage(const char *name)
+{
+       printf("Usage: flashrom [-h|-R|-L|"
+#if CONFIG_PRINT_WIKI == 1
+               "-z|"
+#endif
+               "-p <programmername>[:<parameters>]\n"
+              "                   [-E|-r <file>|-w <file>|-v <file>] [-c <chipname>]\n"
+              "                   [-l <file> [-i <image>]] [-n] [-f]]\n"
+              "                [-V[V[V]]] [-o <logfile>]\n\n");
+
+       printf("Please note that the command line interface for flashrom has "
+                "changed between\n"
+              "0.9.5 and 0.9.6 and will change again before flashrom 1.0.\n"
+              "Do not use flashrom in scripts or other automated tools "
+                "without checking\n"
+              "that your flashrom version won't interpret options in a "
+                "different way.\n\n");
+
+       printf("   -h | --help                       print this help text\n"
+              "   -R | --version                    print version (release)\n"
+              "   -r | --read <file>                read flash and save to "
+                "<file>\n"
+              "   -w | --write <file>               write <file> to flash\n"
+              "   -v | --verify <file>              verify flash against "
+                "<file>\n"
+              "   -E | --erase                      erase flash device\n"
+              "   -V | --verbose                    more verbose output\n"
+              "   -c | --chip <chipname>            probe only for specified "
+                "flash chip\n"
+              "   -f | --force                      force specific operations "
+                "(see man page)\n"
+              "   -n | --noverify                   don't auto-verify\n"
+              "   -l | --layout <file>              read ROM layout from "
+                "<file>\n"
+              "   -i | --image <name>               only flash image <name> "
+                "from flash layout\n"
+              "   -o | --output <name>              log to file <name>\n"
+              "   -L | --list-supported             print supported devices\n"
+#if CONFIG_PRINT_WIKI == 1
+              "   -z | --list-supported-wiki        print supported devices "
+                "in wiki syntax\n"
+#endif
+              "   -p | --programmer <name>[:<param>] specify the programmer "
+                "device\n");
+
+       list_programmers_linebreak(37, 80, 1);
+       printf("\nYou can specify one of -h, -R, -L, "
+#if CONFIG_PRINT_WIKI == 1
+                "-z, "
+#endif
+                "-E, -r, -w, -v or no operation.\n"
+              "If no operation is specified, flashrom will only probe for "
+                "flash chips.\n\n");
+}
+
+static void cli_classic_abort_usage(void)
+{
+       printf("Please run \"flashrom --help\" for usage info.\n");
+       exit(1);
+}
+
+static int check_filename(char *filename, char *type)
+{
+       if (!filename || (filename[0] == '\0')) {
+               fprintf(stderr, "Error: No %s file specified.\n", type);
+               return 1;
+       }
+       /* Not an error, but maybe the user intended to specify a CLI option instead of a file name. */
+       if (filename[0] == '-')
+               fprintf(stderr, "Warning: Supplied %s file name starts with -\n", type);
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       unsigned long size;
+       /* Probe for up to three flash chips. */
+       const struct flashchip *flash;
+       struct flashctx flashes[3];
+       struct flashctx *fill_flash;
+       const char *name;
+       int namelen, opt, i, j;
+       int startchip = -1, chipcount = 0, option_index = 0, force = 0;
+#if CONFIG_PRINT_WIKI == 1
+       int list_supported_wiki = 0;
+#endif
+       int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
+       int dont_verify_it = 0, list_supported = 0, operation_specified = 0;
+       enum programmer prog = PROGRAMMER_INVALID;
+       int ret = 0;
+
+       static const char optstring[] = "r:Rw:v:nVEfc:l:i:p:Lzho:";
+       static const struct option long_options[] = {
+               {"read",                1, NULL, 'r'},
+               {"write",               1, NULL, 'w'},
+               {"erase",               0, NULL, 'E'},
+               {"verify",              1, NULL, 'v'},
+               {"noverify",            0, NULL, 'n'},
+               {"chip",                1, NULL, 'c'},
+               {"verbose",             0, NULL, 'V'},
+               {"force",               0, NULL, 'f'},
+               {"layout",              1, NULL, 'l'},
+               {"image",               1, NULL, 'i'},
+               {"list-supported",      0, NULL, 'L'},
+               {"list-supported-wiki", 0, NULL, 'z'},
+               {"programmer",          1, NULL, 'p'},
+               {"help",                0, NULL, 'h'},
+               {"version",             0, NULL, 'R'},
+               {"output",              1, NULL, 'o'},
+               {NULL,                  0, NULL, 0},
+       };
+
+       char *filename = NULL;
+       char *layoutfile = NULL;
+       char *logfile = NULL;
+       char *tempstr = NULL;
+       char *pparam = NULL;
+
+       print_version();
+       print_banner();
+
+       if (selfcheck())
+               exit(1);
+
+       setbuf(stdout, NULL);
+       /* FIXME: Delay all operation_specified checks until after command
+        * line parsing to allow --help overriding everything else.
+        */
+       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");
+                               cli_classic_abort_usage();
+                       }
+                       filename = strdup(optarg);
+                       read_it = 1;
+                       break;
+               case 'w':
+                       if (++operation_specified > 1) {
+                               fprintf(stderr, "More than one operation "
+                                       "specified. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       filename = strdup(optarg);
+                       write_it = 1;
+                       break;
+               case 'v':
+                       //FIXME: gracefully handle superfluous -v
+                       if (++operation_specified > 1) {
+                               fprintf(stderr, "More than one operation "
+                                       "specified. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       if (dont_verify_it) {
+                               fprintf(stderr, "--verify and --noverify are"
+                                       "mutually exclusive. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       filename = strdup(optarg);
+                       verify_it = 1;
+                       break;
+               case 'n':
+                       if (verify_it) {
+                               fprintf(stderr, "--verify and --noverify are"
+                                       "mutually exclusive. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       dont_verify_it = 1;
+                       break;
+               case 'c':
+                       chip_to_probe = strdup(optarg);
+                       break;
+               case 'V':
+                       verbose_screen++;
+                       if (verbose_screen > MSG_DEBUG2)
+                               verbose_logfile = verbose_screen;
+                       break;
+               case 'E':
+                       if (++operation_specified > 1) {
+                               fprintf(stderr, "More than one operation "
+                                       "specified. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       erase_it = 1;
+                       break;
+               case 'f':
+                       force = 1;
+                       break;
+               case 'l':
+                       if (layoutfile) {
+                               fprintf(stderr, "Error: --layout specified "
+                                       "more than once. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       layoutfile = strdup(optarg);
+                       break;
+               case 'i':
+                       tempstr = strdup(optarg);
+                       if (register_include_arg(tempstr))
+                               cli_classic_abort_usage();
+                       break;
+               case 'L':
+                       if (++operation_specified > 1) {
+                               fprintf(stderr, "More than one operation "
+                                       "specified. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       list_supported = 1;
+                       break;
+               case 'z':
+#if CONFIG_PRINT_WIKI == 1
+                       if (++operation_specified > 1) {
+                               fprintf(stderr, "More than one operation "
+                                       "specified. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       list_supported_wiki = 1;
+#else
+                       fprintf(stderr, "Error: Wiki output was not compiled "
+                               "in. Aborting.\n");
+                       cli_classic_abort_usage();
+#endif
+                       break;
+               case 'p':
+                       if (prog != PROGRAMMER_INVALID) {
+                               fprintf(stderr, "Error: --programmer specified "
+                                       "more than once. You can separate "
+                                       "multiple\nparameters for a programmer "
+                                       "with \",\". Please see the man page "
+                                       "for details.\n");
+                               cli_classic_abort_usage();
+                       }
+                       for (prog = 0; prog < PROGRAMMER_INVALID; prog++) {
+                               name = programmer_table[prog].name;
+                               namelen = strlen(name);
+                               if (strncmp(optarg, name, namelen) == 0) {
+                                       switch (optarg[namelen]) {
+                                       case ':':
+                                               pparam = strdup(optarg + namelen + 1);
+                                               if (!strlen(pparam)) {
+                                                       free(pparam);
+                                                       pparam = NULL;
+                                               }
+                                               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 (prog == PROGRAMMER_INVALID) {
+                               fprintf(stderr, "Error: Unknown programmer \"%s\". Valid choices are:\n",
+                                       optarg);
+                               list_programmers_linebreak(0, 80, 0);
+                               cli_classic_abort_usage();
+                       }
+                       break;
+               case 'R':
+                       /* print_version() is always called during startup. */
+                       if (++operation_specified > 1) {
+                               fprintf(stderr, "More than one operation "
+                                       "specified. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       exit(0);
+                       break;
+               case 'h':
+                       if (++operation_specified > 1) {
+                               fprintf(stderr, "More than one operation "
+                                       "specified. Aborting.\n");
+                               cli_classic_abort_usage();
+                       }
+                       cli_classic_usage(argv[0]);
+                       exit(0);
+                       break;
+               case 'o':
+#ifdef STANDALONE
+                       fprintf(stderr, "Log file not supported in standalone mode. Aborting.\n");
+                       cli_classic_abort_usage();
+#else /* STANDALONE */
+                       logfile = strdup(optarg);
+                       if (logfile[0] == '\0') {
+                               fprintf(stderr, "No log filename specified.\n");
+                               cli_classic_abort_usage();
+                       }
+#endif /* STANDALONE */
+                       break;
+               default:
+                       cli_classic_abort_usage();
+                       break;
+               }
+       }
+
+       if (optind < argc) {
+               fprintf(stderr, "Error: Extra parameter found.\n");
+               cli_classic_abort_usage();
+       }
+
+       if ((read_it | write_it | verify_it) && check_filename(filename, "image")) {
+               cli_classic_abort_usage();
+       }
+       if (layoutfile && check_filename(layoutfile, "layout")) {
+               cli_classic_abort_usage();
+       }
+
+#ifndef STANDALONE
+       if (logfile && check_filename(logfile, "log"))
+               cli_classic_abort_usage();
+       if (logfile && open_logfile(logfile))
+               return 1;
+#endif /* !STANDALONE */
+
+#if CONFIG_PRINT_WIKI == 1
+       if (list_supported_wiki) {
+               print_supported_wiki();
+               ret = 0;
+               goto out;
+       }
+#endif
+
+       if (list_supported) {
+               print_supported();
+               ret = 0;
+               goto out;
+       }
+
+#ifndef STANDALONE
+       start_logging();
+#endif /* !STANDALONE */
+
+       print_buildinfo();
+       msg_gdbg("Command line (%i args):", argc - 1);
+       for (i = 0; i < argc; i++) {
+               msg_gdbg(" %s", argv[i]);
+       }
+       msg_gdbg("\n");
+
+       if (layoutfile && read_romlayout(layoutfile)) {
+               ret = 1;
+               goto out;
+       }
+       if (process_include_args()) {
+               ret = 1;
+               goto out;
+       }
+       /* Does a chip with the requested name exist in the flashchips array? */
+       if (chip_to_probe) {
+               for (flash = flashchips; flash && flash->name; flash++)
+                       if (!strcmp(flash->name, chip_to_probe))
+                               break;
+               if (!flash || !flash->name) {
+                       msg_cerr("Error: Unknown chip '%s' specified.\n", chip_to_probe);
+                       msg_gerr("Run flashrom -L to view the hardware supported in this flashrom version.\n");
+                       ret = 1;
+                       goto out;
+               }
+               /* Clean up after the check. */
+               flash = NULL;
+       }
+
+       if (prog == PROGRAMMER_INVALID) {
+               msg_perr("Please select a programmer with the --programmer parameter.\n"
+                        "Valid choices are:\n");
+               list_programmers_linebreak(0, 80, 0);
+               ret = 1;
+               goto out;
+       }
+
+       /* FIXME: Delay calibration should happen in programmer code. */
+       myusec_calibrate_delay();
+
+       if (programmer_init(prog, pparam)) {
+               msg_perr("Error: Programmer initialization failed.\n");
+               ret = 1;
+               goto out_shutdown;
+       }
+       tempstr = flashbuses_to_text(get_buses_supported());
+       msg_pdbg("The following protocols are supported: %s.\n",
+                tempstr);
+       free(tempstr);
+
+       for (j = 0; j < registered_programmer_count; j++) {
+               startchip = 0;
+               while (chipcount < ARRAY_SIZE(flashes)) {
+                       startchip = probe_flash(&registered_programmers[j],
+                                               startchip, 
+                                               &flashes[chipcount], 0);
+                       if (startchip == -1)
+                               break;
+                       chipcount++;
+                       startchip++;
+               }
+       }
+
+       if (chipcount > 1) {
+               msg_cinfo("Multiple flash chips were detected: \"%s\"", flashes[0].name);
+               for (i = 1; i < chipcount; i++)
+                       msg_cinfo(", \"%s\"", flashes[i].name);
+               msg_cinfo("\nPlease specify which chip to use with the -c <chipname> option.\n");
+               ret = 1;
+               goto out_shutdown;
+       } else if (!chipcount) {
+               msg_cinfo("No EEPROM/flash device found.\n");
+               if (!force || !chip_to_probe) {
+                       msg_cinfo("Note: flashrom can never write if the flash chip isn't found "
+                                 "automatically.\n");
+               }
+               if (force && read_it && chip_to_probe) {
+                       struct registered_programmer *pgm;
+                       int compatible_programmers = 0;
+                       msg_cinfo("Force read (-f -r -c) requested, pretending the chip is there:\n");
+                       /* This loop just counts compatible controllers. */
+                       for (j = 0; j < registered_programmer_count; j++) {
+                               pgm = &registered_programmers[j];
+                               if (pgm->buses_supported & flashes[0].bustype)
+                                       compatible_programmers++;
+                       }
+                       if (compatible_programmers > 1)
+                               msg_cinfo("More than one compatible controller found for the requested flash "
+                                         "chip, using the first one.\n");
+                       for (j = 0; j < registered_programmer_count; j++) {
+                               pgm = &registered_programmers[j];
+                               startchip = probe_flash(pgm, 0, &flashes[0], 1);
+                               if (startchip != -1)
+                                       break;
+                       }
+                       if (startchip == -1) {
+                               msg_cinfo("Probing for flash chip '%s' failed.\n", chip_to_probe);
+                               ret = 1;
+                               goto out_shutdown;
+                       }
+                       msg_cinfo("Please note that forced reads most likely contain garbage.\n");
+                       ret = read_flash_to_file(&flashes[0], filename);
+                       goto out_shutdown;
+               }
+               ret = 1;
+               goto out_shutdown;
+       } else if (!chip_to_probe) {
+               /* repeat for convenience when looking at foreign logs */
+               tempstr = flashbuses_to_text(flashes[0].bustype);
+               msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n",
+                        flashes[0].vendor, flashes[0].name,
+                        flashes[0].total_size, tempstr);
+               free(tempstr);
+       }
+
+       fill_flash = &flashes[0];
+
+       check_chip_supported(fill_flash);
+
+       size = fill_flash->total_size * 1024;
+       if (check_max_decode(fill_flash->pgm->buses_supported & fill_flash->bustype, size) && (!force)) {
+               msg_cerr("Chip is too big for this programmer (-V gives details). Use --force to override.\n");
+               ret = 1;
+               goto out_shutdown;
+       }
+
+       if (!(read_it | write_it | verify_it | erase_it)) {
+               msg_ginfo("No operations were specified.\n");
+               goto out_shutdown;
+       }
+
+       /* Always verify write operations unless -n is used. */
+       if (write_it && !dont_verify_it)
+               verify_it = 1;
+
+       /* FIXME: We should issue an unconditional chip reset here. This can be
+        * done once we have a .reset function in struct flashchip.
+        * Give the chip time to settle.
+        */
+       programmer_delay(100000);
+       ret |= doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it);
+       /* Note: doit() already calls programmer_shutdown(). */
+       goto out;
+
+out_shutdown:
+       programmer_shutdown();
+out:
+#ifndef STANDALONE
+       ret |= close_logfile();
+#endif /* !STANDALONE */
+       return ret;
+}
diff --git a/cli_output.c b/cli_output.c
new file mode 100644 (file)
index 0000000..57a0a05
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ * Copyright (C) 2011 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "flash.h"
+
+#ifndef STANDALONE
+static FILE *logfile = NULL;
+
+int close_logfile(void)
+{
+       if (!logfile)
+               return 0;
+       /* No need to call fflush() explicitly, fclose() already does that. */
+       if (fclose(logfile)) {
+               /* fclose returned an error. Stop writing to be safe. */
+               logfile = NULL;
+               msg_perr("Closing the log file returned error %s\n", strerror(errno));
+               return 1;
+       }
+       logfile = NULL;
+       return 0;
+}
+
+int open_logfile(const char * const filename)
+{
+       if (!filename) {
+               msg_gerr("No filename specified.\n");
+               return 1;
+       }
+       if ((logfile = fopen(filename, "w")) == NULL) {
+               perror(filename);
+               return 1;
+       }
+       return 0;
+}
+
+void start_logging(void)
+{
+       enum msglevel oldverbose_screen = verbose_screen;
+
+       /* Shut up the console. */
+       verbose_screen = MSG_ERROR;
+       print_version();
+       verbose_screen = oldverbose_screen;
+}
+#endif /* !STANDALONE */
+
+/* Please note that level is the verbosity, not the importance of the message. */
+int print(enum msglevel level, const char *fmt, ...)
+{
+       va_list ap;
+       int ret = 0;
+       FILE *output_type = stdout;
+
+       if (level == MSG_ERROR)
+               output_type = stderr;
+
+       if (level <= verbose_screen) {
+               va_start(ap, fmt);
+               ret = vfprintf(output_type, fmt, ap);
+               va_end(ap);
+               /* msg_*spew usually happens inside chip accessors in possibly
+                * time-critical operations. Don't slow them down by flushing.
+                */
+               if (level != MSG_SPEW)
+                       fflush(output_type);
+       }
+#ifndef STANDALONE
+       if ((level <= verbose_logfile) && logfile) {
+               va_start(ap, fmt);
+               ret = vfprintf(logfile, fmt, ap);
+               va_end(ap);
+               if (level != MSG_SPEW)
+                       fflush(logfile);
+       }
+#endif /* !STANDALONE */
+       return ret;
+}
diff --git a/coreboot_tables.h b/coreboot_tables.h
new file mode 100644 (file)
index 0000000..2e96526
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2002 Linux Networx
+ * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
+ * Copyright (C) 2005-2007 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
+ */
+
+#ifndef COREBOOT_TABLES_H
+#define COREBOOT_TABLES_H
+
+#include <stdint.h>
+
+/* 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 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/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.
+ *
+ * The completeness test for the information in this table is:
+ * - Can all of the hardware be detected?
+ * - Are the per motherboard constants available?
+ * - Is there enough to allow a kernel to run that was written before
+ *   a particular motherboard is constructed? (Assuming the kernel
+ *   has drivers for all of the hardware but it does not have
+ *   assumptions on how the hardware is connected together).
+ *
+ * With this test it should be straight forward to determine if a
+ * 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 expedite to include extra
+ * table entries and be backwards compatible, but it is not required.
+ */
+
+/* Since coreboot is usually compiled 32bit, gcc will align 64bit 
+ * types to 32bit boundaries. If the coreboot table is dumped on a 
+ * 64bit system, a uint64_t would be aligned to 64bit boundaries, 
+ * breaking the table format.
+ *
+ * lb_uint64 will keep 64bit coreboot table values aligned to 32bit
+ * to ensure compatibility. They can be accessed with the two functions
+ * below: unpack_lb64() and pack_lb64()
+ *
+ * See also: util/lbtdump/lbtdump.c
+ */
+
+struct lb_uint64 {
+       uint32_t lo;
+       uint32_t hi;
+};
+
+struct lb_header {
+       uint8_t signature[4];   /* LBIO */
+       uint32_t header_bytes;
+       uint32_t header_checksum;
+       uint32_t table_bytes;
+       uint32_t table_checksum;
+       uint32_t table_entries;
+};
+
+/* 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 environment record if you don't know what it easy.  This allows
+ * forward compatibility with records not yet defined.
+ */
+struct lb_record {
+       uint32_t tag;           /* tag ID */
+       uint32_t size;          /* size of record (in bytes) */
+};
+
+#define LB_TAG_UNUSED  0x0000
+
+#define LB_TAG_MEMORY  0x0001
+
+struct lb_memory_range {
+       struct lb_uint64 start;
+       struct lb_uint64 size;
+       uint32_t type;
+#define LB_MEM_RAM       1     /* Memory anyone can use */
+#define LB_MEM_RESERVED  2     /* Don't use this memory region */
+#define LB_MEM_TABLE     16    /* Ram configuration tables are kept in */
+};
+
+struct lb_memory {
+       uint32_t tag;
+       uint32_t size;
+       struct lb_memory_range map[0];
+};
+
+#define LB_TAG_HWRPB   0x0002
+struct lb_hwrpb {
+       uint32_t tag;
+       uint32_t size;
+       uint64_t hwrpb;
+};
+
+#define LB_TAG_MAINBOARD       0x0003
+struct lb_mainboard {
+       uint32_t tag;
+       uint32_t size;
+       uint8_t vendor_idx;
+       uint8_t part_number_idx;
+       uint8_t strings[0];
+};
+
+#define LB_TAG_VERSION         0x0004
+#define LB_TAG_EXTRA_VERSION   0x0005
+#define LB_TAG_BUILD           0x0006
+#define LB_TAG_COMPILE_TIME    0x0007
+#define LB_TAG_COMPILE_BY      0x0008
+#define LB_TAG_COMPILE_HOST    0x0009
+#define LB_TAG_COMPILE_DOMAIN  0x000a
+#define LB_TAG_COMPILER                0x000b
+#define LB_TAG_LINKER          0x000c
+#define LB_TAG_ASSEMBLER       0x000d
+struct lb_string {
+       uint32_t tag;
+       uint32_t size;
+       uint8_t string[0];
+};
+
+#define LB_TAG_FORWARD         0x0011
+struct lb_forward {
+       uint32_t tag;
+       uint32_t size;
+       uint64_t forward;
+};
+
+#endif                         /* COREBOOT_TABLES_H */
diff --git a/dediprog.c b/dediprog.c
new file mode 100644 (file)
index 0000000..9559eed
--- /dev/null
@@ -0,0 +1,922 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <usb.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "spi.h"
+
+#define FIRMWARE_VERSION(x,y,z) ((x << 16) | (y << 8) | z)
+#define DEFAULT_TIMEOUT 3000
+static usb_dev_handle *dediprog_handle;
+static int dediprog_firmwareversion;
+static int dediprog_endpoint;
+
+#define DEDI_SPI_CMD_PAGEWRITE 0x1
+#define DEDI_SPI_CMD_AAIWRITE  0x4
+
+#if 0
+/* Might be useful for other pieces of code as well. */
+static void print_hex(void *buf, size_t len)
+{
+       size_t i;
+
+       for (i = 0; i < len; i++)
+               msg_pdbg(" %02x", ((uint8_t *)buf)[i]);
+}
+#endif
+
+/* Might be useful for other USB devices as well. static for now. */
+static 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);
+
+/* Set/clear LEDs on dediprog */
+#define PASS_ON                (0 << 0)
+#define PASS_OFF       (1 << 0)
+#define BUSY_ON                (0 << 1)
+#define BUSY_OFF       (1 << 1)
+#define ERROR_ON       (0 << 2)
+#define ERROR_OFF      (1 << 2)
+static int current_led_status = -1;
+
+static int dediprog_set_leds(int leds)
+{
+       int ret, target_leds;
+
+       if (leds < 0 || leds > 7)
+               leds = 0; // Bogus value, enable all LEDs
+
+       if (leds == current_led_status)
+               return 0;
+
+       /* Older Dediprogs with 2.x.x and 3.x.x firmware only had
+        * two LEDs, and they were reversed. So map them around if 
+        * we have an old device. On those devices the LEDs map as
+        * follows:
+        *   bit 2 == 0: green light is on.
+        *   bit 0 == 0: red light is on. 
+        */
+       if (dediprog_firmwareversion < FIRMWARE_VERSION(5,0,0)) {
+               target_leds = ((leds & ERROR_OFF) >> 2) | 
+                       ((leds & PASS_OFF) << 2);
+       } else {
+               target_leds = leds;
+       }
+
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, target_leds,
+                             NULL, 0x0, DEFAULT_TIMEOUT);
+       if (ret != 0x0) {
+               msg_perr("Command Set LED 0x%x failed (%s)!\n",
+                        leds, usb_strerror());
+               return 1;
+       }
+
+       current_led_status = leds;
+
+       return 0;
+}
+
+static int dediprog_set_spi_voltage(int millivolt)
+{
+       int ret;
+       uint16_t voltage_selector;
+
+       switch (millivolt) {
+       case 0:
+               /* Admittedly this one is an assumption. */
+               voltage_selector = 0x0;
+               break;
+       case 1800:
+               voltage_selector = 0x12;
+               break;
+       case 2500:
+               voltage_selector = 0x11;
+               break;
+       case 3500:
+               voltage_selector = 0x10;
+               break;
+       default:
+               msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
+               return 1;
+       }
+       msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
+                millivolt % 1000);
+
+       if (voltage_selector == 0) {
+               /* Wait some time as the original driver does. */
+               programmer_delay(200 * 1000);
+       }
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x9, voltage_selector,
+                             0xff, NULL, 0x0, DEFAULT_TIMEOUT);
+       if (ret != 0x0) {
+               msg_perr("Command Set SPI Voltage 0x%x failed!\n",
+                        voltage_selector);
+               return 1;
+       }
+       if (voltage_selector != 0) {
+               /* Wait some time as the original driver does. */
+               programmer_delay(200 * 1000);
+       }
+       return 0;
+}
+
+#if 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.
+ */
+static 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;
+}
+#endif
+
+/* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes.
+ * @start      start address
+ * @len                length
+ * @return     0 on success, 1 on failure
+ */
+static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf,
+                                 unsigned int start, unsigned int len)
+{
+       int ret;
+       unsigned int i;
+       /* chunksize must be 512, other sizes will NOT work at all. */
+       const unsigned int chunksize = 0x200;
+       const unsigned int count = len / chunksize;
+       const char count_and_chunk[] = {count & 0xff,
+                                       (count >> 8) & 0xff,
+                                       chunksize & 0xff,
+                                       (chunksize >> 8) & 0xff};
+
+       if ((start % chunksize) || (len % chunksize)) {
+               msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug "
+                        "at flashrom@flashrom.org\n", __func__, start, len);
+               return 1;
+       }
+
+       /* No idea if the hardware can handle empty reads, so chicken out. */
+       if (!len)
+               return 0;
+       /* Command Read SPI Bulk. No idea which read command is used on the
+        * SPI side.
+        */
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x20, start % 0x10000,
+                             start / 0x10000, (char *)count_and_chunk,
+                             sizeof(count_and_chunk), DEFAULT_TIMEOUT);
+       if (ret != sizeof(count_and_chunk)) {
+               msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret,
+                        usb_strerror());
+               return 1;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint,
+                                   (char *)buf + i * chunksize, chunksize,
+                                   DEFAULT_TIMEOUT);
+               if (ret != chunksize) {
+                       msg_perr("SPI bulk read %i failed, expected %i, got %i "
+                                "%s!\n", i, chunksize, ret, usb_strerror());
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf,
+                            unsigned int start, unsigned int len)
+{
+       int ret;
+       /* chunksize must be 512, other sizes will NOT work at all. */
+       const unsigned int chunksize = 0x200;
+       unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0;
+       unsigned int bulklen;
+
+       dediprog_set_leds(PASS_OFF|BUSY_ON|ERROR_OFF);
+
+       if (residue) {
+               msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
+                        start, residue);
+               ret = spi_read_chunked(flash, buf, start, residue, 16);
+               if (ret) {
+                       dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+                       return ret;
+               }
+       }
+
+       /* Round down. */
+       bulklen = (len - residue) / chunksize * chunksize;
+       ret = dediprog_spi_bulk_read(flash, buf + residue, start + residue,
+                                    bulklen);
+       if (ret) {
+               dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+               return ret;
+       }
+
+       len -= residue + bulklen;
+       if (len) {
+               msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
+                        start, len);
+               ret = spi_read_chunked(flash, buf + residue + bulklen,
+                                      start + residue + bulklen, len, 16);
+               if (ret) {
+                       dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+                       return ret;
+               }
+       }
+
+       dediprog_set_leds(PASS_ON|BUSY_OFF|ERROR_OFF);
+       return 0;
+}
+
+/* Bulk write interface, will write multiple chunksize byte chunks aligned to chunksize bytes.
+ * @chunksize       length of data chunks, only 256 supported by now
+ * @start           start address
+ * @len             length
+ * @dedi_spi_cmd    dediprog specific write command for spi bus
+ * @return          0 on success, 1 on failure
+ */
+static int dediprog_spi_bulk_write(struct flashctx *flash, uint8_t *buf, unsigned int chunksize,
+                                  unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
+{
+       int ret;
+       unsigned int i;
+       /* USB transfer size must be 512, other sizes will NOT work at all.
+        * chunksize is the real data size per USB bulk transfer. The remaining
+        * space in a USB bulk transfer must be filled with 0xff padding.
+        */
+       const unsigned int count = len / chunksize;
+       const char count_and_cmd[] = {count & 0xff, (count >> 8) & 0xff, 0x00, dedi_spi_cmd};
+       char usbbuf[512];
+
+       /*
+        * We should change this check to
+        *   chunksize > 512
+        * once we know how to handle different chunk sizes.
+        */
+       if (chunksize != 256) {
+               msg_perr("%s: Chunk sizes other than 256 bytes are unsupported, chunksize=%u!\n"
+                        "Please report a bug at flashrom@flashrom.org\n", __func__, chunksize);
+               return 1;
+       }
+
+       if ((start % chunksize) || (len % chunksize)) {
+               msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug "
+                        "at flashrom@flashrom.org\n", __func__, start, len);
+               return 1;
+       }
+
+       /* No idea if the hardware can handle empty writes, so chicken out. */
+       if (!len)
+               return 0;
+       /* Command Write SPI Bulk. No idea which write command is used on the
+        * SPI side.
+        */
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x30, start % 0x10000, start / 0x10000,
+                             (char *)count_and_cmd, sizeof(count_and_cmd), DEFAULT_TIMEOUT);
+       if (ret != sizeof(count_and_cmd)) {
+               msg_perr("Command Write SPI Bulk failed, %i %s!\n", ret,
+                        usb_strerror());
+               return 1;
+       }
+
+       for (i = 0; i < count; i++) {
+               memset(usbbuf, 0xff, sizeof(usbbuf));
+               memcpy(usbbuf, buf + i * chunksize, chunksize);
+               ret = usb_bulk_write(dediprog_handle, dediprog_endpoint,
+                                   usbbuf, 512,
+                                   DEFAULT_TIMEOUT);
+               if (ret != 512) {
+                       msg_perr("SPI bulk write failed, expected %i, got %i "
+                                "%s!\n", 512, ret, usb_strerror());
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int dediprog_spi_write(struct flashctx *flash, uint8_t *buf,
+                             unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
+{
+       int ret;
+       const unsigned int chunksize = flash->page_size;
+       unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0;
+       unsigned int bulklen;
+
+       dediprog_set_leds(PASS_OFF|BUSY_ON|ERROR_OFF);
+
+       if (chunksize != 256) {
+               msg_pdbg("Page sizes other than 256 bytes are unsupported as "
+                        "we don't know how dediprog\nhandles them.\n");
+               /* Write everything like it was residue. */
+               residue = len;
+       }
+
+       if (residue) {
+               msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
+                        start, residue);
+               /* No idea about the real limit. Maybe 12, maybe more. */
+               ret = spi_write_chunked(flash, buf, start, residue, 12);
+               if (ret) {
+                       dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+                       return ret;
+               }
+       }
+
+       /* Round down. */
+       bulklen = (len - residue) / chunksize * chunksize;
+       ret = dediprog_spi_bulk_write(flash, buf + residue, chunksize, start + residue, bulklen, dedi_spi_cmd);
+       if (ret) {
+               dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+               return ret;
+       }
+
+       len -= residue + bulklen;
+       if (len) {
+               msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
+                        start, len);
+               ret = spi_write_chunked(flash, buf + residue + bulklen,
+                                       start + residue + bulklen, len, 12);
+               if (ret) {
+                       dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+                       return ret;
+               }
+       }
+
+       dediprog_set_leds(PASS_ON|BUSY_OFF|ERROR_OFF);
+       return 0;
+}
+
+static int dediprog_spi_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+       return dediprog_spi_write(flash, buf, start, len, DEDI_SPI_CMD_PAGEWRITE);
+}
+
+static int dediprog_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+       return dediprog_spi_write(flash, buf, start, len, DEDI_SPI_CMD_AAIWRITE);
+}
+
+static int dediprog_spi_send_command(struct flashctx *flash,
+                                    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 > 16) {
+               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;
+}
+
+static int dediprog_check_devicestring(void)
+{
+       int ret;
+       int fw[3];
+       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;
+       }
+       if (sscanf(buf, "SF100 V:%d.%d.%d ", &fw[0], &fw[1], &fw[2]) != 3) {
+               msg_perr("Unexpected firmware version string!\n");
+               return 1;
+       }
+       /* Only these versions were tested. */
+       if (fw[0] < 2 || fw[0] > 5) {
+               msg_perr("Unexpected firmware version %d.%d.%d!\n", fw[0],
+                        fw[1], fw[2]);
+               return 1;
+       }
+       dediprog_firmwareversion = FIRMWARE_VERSION(fw[0], fw[1], fw[2]);
+       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).
+ */
+static 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 < 0) {
+               msg_perr("Command A failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       if ((ret != 0x1) || (buf[0] != 0x6f)) {
+               msg_perr("Unexpected response to Command A!\n");
+               return 1;
+       }
+       return 0;
+}
+
+#if 0
+/* Something.
+ * Present in eng_detect_blink.log with firmware 3.1.8
+ * Always preceded by Command Receive Device String
+ */
+static int dediprog_command_b(void)
+{
+       int ret;
+       char buf[0x3];
+
+       memset(buf, 0, sizeof(buf));
+       ret = usb_control_msg(dediprog_handle, 0xc3, 0x7, 0x0, 0xef00, buf,
+                             0x3, DEFAULT_TIMEOUT);
+       if (ret < 0) {
+               msg_perr("Command B failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       if ((ret != 0x3) || (buf[0] != 0xff) || (buf[1] != 0xff) ||
+           (buf[2] != 0xff)) {
+               msg_perr("Unexpected response to Command B!\n");
+               return 1;
+       }
+
+       return 0;
+}
+#endif
+
+/* 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.
+ */
+static 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("Command C failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       return 0;
+}
+
+#if 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.
+ * Present in all logs with Firmware 2.1.1 and 3.1.8
+ */
+static 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);
+       /* This check is most probably wrong. Command F always causes a timeout
+        * in the logs, so we should check for timeout instead of checking for
+        * success.
+        */
+       if (ret != 0x1) {
+               msg_perr("Command F failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       return 0;
+}
+
+/* Start/stop blinking?
+ * Present in eng_detect_blink.log with firmware 3.1.8
+ * Preceded by Command J
+ */
+static int dediprog_command_g(void)
+{
+       int ret;
+
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x03, NULL, 0x0, DEFAULT_TIMEOUT);
+       if (ret != 0x0) {
+               msg_perr("Command G failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       return 0;
+}
+
+/* Something.
+ * Present in all logs with firmware 5.1.5
+ * Always preceded by Command Receive Device String
+ * Always followed by Command Set SPI Voltage nonzero
+ */
+static int dediprog_command_h(void)
+{
+       int ret;
+
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x05, NULL, 0x0, DEFAULT_TIMEOUT);
+       if (ret != 0x0) {
+               msg_perr("Command H failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       return 0;
+}
+
+/* Shutdown for firmware 5.x?
+ * Present in all logs with firmware 5.1.5
+ * Often preceded by a SPI operation (Command Read SPI Bulk or Receive SPI)
+ * Always followed by Command Set SPI Voltage 0x0000
+ */
+static int dediprog_command_i(void)
+{
+       int ret;
+
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x06, NULL, 0x0, DEFAULT_TIMEOUT);
+       if (ret != 0x0) {
+               msg_perr("Command I failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       return 0;
+}
+
+/* Start/stop blinking?
+ * Present in all logs with firmware 5.1.5
+ * Always preceded by Command Receive Device String on 5.1.5
+ * Always followed by Command Set SPI Voltage nonzero on 5.1.5
+ * Present in eng_detect_blink.log with firmware 3.1.8
+ * Preceded by Command B in eng_detect_blink.log
+ * Followed by Command G in eng_detect_blink.log
+ */
+static int dediprog_command_j(void)
+{
+       int ret;
+
+       ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x07, NULL, 0x0, DEFAULT_TIMEOUT);
+       if (ret != 0x0) {
+               msg_perr("Command J failed (%s)!\n", usb_strerror());
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+static int parse_voltage(char *voltage)
+{
+       char *tmp = NULL;
+       int i;
+       int millivolt = 0, fraction = 0;
+
+       if (!voltage || !strlen(voltage)) {
+               msg_perr("Empty voltage= specified.\n");
+               return -1;
+       }
+       millivolt = (int)strtol(voltage, &tmp, 0);
+       voltage = tmp;
+       /* Handle "," and "." as decimal point. Everything after it is assumed
+        * to be in decimal notation.
+        */
+       if ((*voltage == '.') || (*voltage == ',')) {
+               voltage++;
+               for (i = 0; i < 3; i++) {
+                       fraction *= 10;
+                       /* Don't advance if the current character is invalid,
+                        * but continue multiplying.
+                        */
+                       if ((*voltage < '0') || (*voltage > '9'))
+                               continue;
+                       fraction += *voltage - '0';
+                       voltage++;
+               }
+               /* Throw away remaining digits. */
+               voltage += strspn(voltage, "0123456789");
+       }
+       /* The remaining string must be empty or "mV" or "V". */
+       tolower_string(voltage);
+
+       /* No unit or "V". */
+       if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
+               millivolt *= 1000;
+               millivolt += fraction;
+       } else if (!strncmp(voltage, "mv", 2) ||
+                  !strncmp(voltage, "milliv", 6)) {
+               /* No adjustment. fraction is discarded. */
+       } else {
+               /* Garbage at the end of the string. */
+               msg_perr("Garbage voltage= specified.\n");
+               return -1;
+       }
+       return millivolt;
+}
+
+static const struct spi_programmer spi_programmer_dediprog = {
+       .type           = SPI_CONTROLLER_DEDIPROG,
+       .max_data_read  = MAX_DATA_UNSPECIFIED,
+       .max_data_write = MAX_DATA_UNSPECIFIED,
+       .command        = dediprog_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = dediprog_spi_read,
+       .write_256      = dediprog_spi_write_256,
+       .write_aai      = dediprog_spi_write_aai,
+};
+
+static int dediprog_shutdown(void *data)
+{
+       msg_pspew("%s\n", __func__);
+
+#if 0
+       /* Shutdown on firmware 5.x */
+       if (dediprog_firmwareversion == 5)
+               if (dediprog_command_i())
+                       return 1;
+#endif
+
+       /* URB 28. Command Set SPI Voltage to 0. */
+       if (dediprog_set_spi_voltage(0x0))
+               return 1;
+
+       if (usb_release_interface(dediprog_handle, 0)) {
+               msg_perr("Could not release USB interface!\n");
+               return 1;
+       }
+       if (usb_close(dediprog_handle)) {
+               msg_perr("Could not close USB device!\n");
+               return 1;
+       }
+       return 0;
+}
+
+/* URB numbers refer to the first log ever captured. */
+int dediprog_init(void)
+{
+       struct usb_device *dev;
+       char *voltage;
+       int millivolt = 3500;
+       int ret;
+
+       msg_pspew("%s\n", __func__);
+
+       voltage = extract_programmer_param("voltage");
+       if (voltage) {
+               millivolt = parse_voltage(voltage);
+               free(voltage);
+               if (millivolt < 0)
+                       return 1;
+               msg_pinfo("Setting voltage to %i mV\n", millivolt);
+       }
+
+       /* 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);
+       ret = usb_set_configuration(dediprog_handle, 1);
+       if (ret < 0) {
+               msg_perr("Could not set USB device configuration: %i %s\n",
+                        ret, usb_strerror());
+               if (usb_close(dediprog_handle))
+                       msg_perr("Could not close USB device!\n");
+               return 1;
+       }
+       ret = usb_claim_interface(dediprog_handle, 0);
+       if (ret < 0) {
+               msg_perr("Could not claim USB device interface %i: %i %s\n",
+                        0, ret, usb_strerror());
+               if (usb_close(dediprog_handle))
+                       msg_perr("Could not close USB device!\n");
+               return 1;
+       }
+       dediprog_endpoint = 2;
+       
+       if (register_shutdown(dediprog_shutdown, NULL))
+               return 1;
+
+       dediprog_set_leds(PASS_ON|BUSY_ON|ERROR_ON);
+
+       /* URB 6. Command A. */
+       if (dediprog_command_a()) {
+               dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+               return 1;
+       }
+       /* URB 7. Command A. */
+       if (dediprog_command_a()) {
+               dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+               return 1;
+       }
+       /* URB 8. Command Prepare Receive Device String. */
+       /* URB 9. Command Receive Device String. */
+       if (dediprog_check_devicestring()) {
+               dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+               return 1;
+       }
+       /* URB 10. Command C. */
+       if (dediprog_command_c()) {
+               dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+               return 1;
+       }
+       /* URB 11. Command Set SPI Voltage. */
+       if (dediprog_set_spi_voltage(millivolt)) {
+               dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
+               return 1;
+       }
+
+       register_spi_programmer(&spi_programmer_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
+
+       dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_OFF);
+
+       return 0;
+}
+
+#if 0
+/* Leftovers from reverse engineering. Keep for documentation purposes until
+ * completely understood.
+ */
+static 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);
+       /* 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 Start Bulk Read. Data is u16 blockcount, u16 blocksize. */
+       /* Command Start Bulk Write. Data is u16 blockcount, u16 blocksize. */
+       /* Bulk transfer sizes for Command Start Bulk Read/Write are always
+        * 512 bytes, rest is filled with 0xff.
+        */
+
+       return 0;
+}
+#endif 
diff --git a/dmi.c b/dmi.c
new file mode 100644 (file)
index 0000000..2c2551d
--- /dev/null
+++ b/dmi.c
@@ -0,0 +1,250 @@
+/*
+ * 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "flash.h"
+#include "programmer.h"
+
+int has_dmi_support = 0;
+
+#if STANDALONE
+
+/* Stub to indicate missing DMI functionality.
+ * has_dmi_support is 0 by default, so nothing to do here.
+ * Because dmidecode is not available on all systems, the goal is to implement
+ * the DMI subset we need directly in this file.
+ */
+void dmi_init(void)
+{
+}
+
+int dmi_match(const char *pattern)
+{
+       return 0;
+}
+
+#else /* STANDALONE */
+
+static const char *dmidecode_names[] = {
+       "system-manufacturer",
+       "system-product-name",
+       "system-version",
+       "baseboard-manufacturer",
+       "baseboard-product-name",
+       "baseboard-version",
+};
+
+/* This list is used to identify supposed laptops. The is_laptop field has the
+ * following meaning:
+ *     - 0: in all likelihood not a laptop
+ *     - 1: in all likelihood a laptop
+ *     - 2: chassis-type is not specific enough
+ * A full list of chassis types can be found in the System Management BIOS
+ * (SMBIOS) Reference Specification 2.7.0 section 7.4.1 "Chassis Types" at
+ * http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.0.pdf
+ * The types below are the most common ones.
+ */
+static const struct {
+       unsigned char type;
+       unsigned char is_laptop;
+       const char *name;
+} dmi_chassis_types[] = {
+       {0x01, 2, "Other"},
+       {0x02, 2, "Unknown"},
+       {0x03, 0, "Desktop"},
+       {0x04, 0, "Low Profile Desktop"},
+       {0x06, 0, "Mini Tower"},
+       {0x07, 0, "Tower"},
+       {0x08, 1, "Portable"},
+       {0x09, 1, "Laptop"},
+       {0x0a, 1, "Notebook"},
+       {0x0b, 1, "Hand Held"},
+       {0x0e, 1, "Sub Notebook"},
+       {0x11, 0, "Main Server Chassis"},
+       {0x17, 0, "Rack Mount Chassis"},
+       {0x18, 0, "Sealed-case PC"}, /* used by Supermicro (X8SIE) */
+};
+
+#define DMI_COMMAND_LEN_MAX 260
+static const char *dmidecode_command = "dmidecode";
+
+static 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) {
+               msg_perr("DMI pipe open error\n");
+               return NULL;
+       }
+
+       /* Kill lines starting with '#', as recent dmidecode versions
+        * have the quirk to emit a "# SMBIOS implementations newer..."
+        * message even on "-s" if the SMBIOS declares a
+        * newer-than-supported version number, while it *should* only print
+        * the requested string.
+        */
+       do {
+               if (!fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe)) {
+                       if (ferror(dmidecode_pipe)) {
+                               msg_perr("DMI pipe read error\n");
+                               pclose(dmidecode_pipe);
+                               return NULL;
+                       } else {
+                               answerbuf[0] = 0;       /* Hit EOF */
+                       }
+               }
+       } while (answerbuf[0] == '#');
+
+       /* 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) {
+               msg_pinfo("dmidecode execution unsuccessful - continuing "
+                         "without DMI info\n");
+               return NULL;
+       }
+
+       /* Chomp trailing newline. */
+       if (answerbuf[0] != 0 && answerbuf[strlen(answerbuf) - 1] == '\n')
+               answerbuf[strlen(answerbuf) - 1] = 0;
+       msg_pdbg("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 == NULL)
+               return;
+
+       is_laptop = 2;
+       for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) {
+               if (strcasecmp(chassis_type, dmi_chassis_types[i].name) == 0) {
+                       is_laptop = dmi_chassis_types[i].is_laptop;
+                       break;
+               }
+       }
+
+       switch (is_laptop) {
+       case 1:
+               msg_pdbg("Laptop detected via DMI.\n");
+               break;
+       case 2:
+               msg_pdbg("DMI chassis-type is not specific enough.\n");
+               break;
+       }
+       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;
+
+       msg_pspew("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;
+}
+
+#endif /* STANDALONE */
diff --git a/drkaiser.c b/drkaiser.c
new file mode 100644 (file)
index 0000000..259530a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Joerg Fischer <turboj@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_DRKAISER         0x1803
+
+#define PCI_MAGIC_DRKAISER_ADDR                0x50
+#define PCI_MAGIC_DRKAISER_VALUE       0xa971
+
+#define DRKAISER_MEMMAP_SIZE           (1024 * 128)
+
+/* Mask to restrict flash accesses to the 128kB memory window. */
+#define DRKAISER_MEMMAP_MASK           ((1 << 17) - 1)
+
+const struct pcidev_status drkaiser_pcidev[] = {
+       {0x1803, 0x5057, OK, "Dr. Kaiser", "PC-Waechter (Actel FPGA)"},
+       {},
+};
+
+static uint8_t *drkaiser_bar;
+
+static void drkaiser_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                chipaddr addr);
+static uint8_t drkaiser_chip_readb(const struct flashctx *flash,
+                                  const chipaddr addr);
+static const struct par_programmer par_programmer_drkaiser = {
+               .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,
+};
+
+static int drkaiser_shutdown(void *data)
+{
+       physunmap(drkaiser_bar, DRKAISER_MEMMAP_SIZE);
+       /* Flash write is disabled automatically by PCI restore. */
+       pci_cleanup(pacc);
+       return 0;
+};
+
+int drkaiser_init(void)
+{
+       uint32_t addr;
+
+       if (rget_io_perms())
+               return 1;
+
+       addr = pcidev_init(PCI_BASE_ADDRESS_2, drkaiser_pcidev);
+
+       /* Write magic register to enable flash write. */
+       rpci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR,
+                       PCI_MAGIC_DRKAISER_VALUE);
+
+       /* Map 128kB flash memory window. */
+       drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory",
+                              addr, DRKAISER_MEMMAP_SIZE);
+
+       if (register_shutdown(drkaiser_shutdown, NULL))
+               return 1;
+
+       max_rom_decode.parallel = 128 * 1024;
+       register_par_programmer(&par_programmer_drkaiser, BUS_PARALLEL);
+
+       return 0;
+}
+
+static void drkaiser_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                chipaddr addr)
+{
+       pci_mmio_writeb(val, drkaiser_bar + (addr & DRKAISER_MEMMAP_MASK));
+}
+
+static uint8_t drkaiser_chip_readb(const struct flashctx *flash,
+                                  const chipaddr addr)
+{
+       return pci_mmio_readb(drkaiser_bar + (addr & DRKAISER_MEMMAP_MASK));
+}
diff --git a/dummyflasher.c b/dummyflasher.c
new file mode 100644 (file)
index 0000000..66d0df0
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ * 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; 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+
+/* Remove the #define below if you don't want SPI flash chip emulation. */
+#define EMULATE_SPI_CHIP 1
+
+#if EMULATE_SPI_CHIP
+#define EMULATE_CHIP 1
+#include "spi.h"
+#endif
+
+#if EMULATE_CHIP
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#if EMULATE_CHIP
+static uint8_t *flashchip_contents = NULL;
+enum emu_chip {
+       EMULATE_NONE,
+       EMULATE_ST_M25P10_RES,
+       EMULATE_SST_SST25VF040_REMS,
+       EMULATE_SST_SST25VF032B,
+       EMULATE_MACRONIX_MX25L6436,
+};
+static enum emu_chip emu_chip = EMULATE_NONE;
+static char *emu_persistent_image = NULL;
+static unsigned int emu_chip_size = 0;
+#if EMULATE_SPI_CHIP
+static unsigned int emu_max_byteprogram_size = 0;
+static unsigned int emu_max_aai_size = 0;
+static unsigned int emu_jedec_se_size = 0;
+static unsigned int emu_jedec_be_52_size = 0;
+static unsigned int emu_jedec_be_d8_size = 0;
+static unsigned int emu_jedec_ce_60_size = 0;
+static unsigned int emu_jedec_ce_c7_size = 0;
+unsigned char spi_blacklist[256];
+unsigned char spi_ignorelist[256];
+int spi_blacklist_size = 0;
+int spi_ignorelist_size = 0;
+static uint8_t emu_status = 0;
+
+/* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
+static const uint8_t const sfdp_table[] = {
+       0x53, 0x46, 0x44, 0x50, // @0x00: SFDP signature
+       0x00, 0x01, 0x01, 0xFF, // @0x04: revision 1.0, 2 headers
+       0x00, 0x00, 0x01, 0x09, // @0x08: JEDEC SFDP header rev. 1.0, 9 DW long
+       0x1C, 0x00, 0x00, 0xFF, // @0x0C: PTP0 = 0x1C (instead of 0x30)
+       0xC2, 0x00, 0x01, 0x04, // @0x10: Macronix header rev. 1.0, 4 DW long
+       0x48, 0x00, 0x00, 0xFF, // @0x14: PTP1 = 0x48 (instead of 0x60)
+       0xFF, 0xFF, 0xFF, 0xFF, // @0x18: hole.
+       0xE5, 0x20, 0xC9, 0xFF, // @0x1C: SFDP parameter table start
+       0xFF, 0xFF, 0xFF, 0x03, // @0x20
+       0x00, 0xFF, 0x08, 0x6B, // @0x24
+       0x08, 0x3B, 0x00, 0xFF, // @0x28
+       0xEE, 0xFF, 0xFF, 0xFF, // @0x2C
+       0xFF, 0xFF, 0x00, 0x00, // @0x30
+       0xFF, 0xFF, 0x00, 0xFF, // @0x34
+       0x0C, 0x20, 0x0F, 0x52, // @0x38
+       0x10, 0xD8, 0x00, 0xFF, // @0x3C: SFDP parameter table end
+       0xFF, 0xFF, 0xFF, 0xFF, // @0x40: hole.
+       0xFF, 0xFF, 0xFF, 0xFF, // @0x44: hole.
+       0x00, 0x36, 0x00, 0x27, // @0x48: Macronix parameter table start
+       0xF4, 0x4F, 0xFF, 0xFF, // @0x4C
+       0xD9, 0xC8, 0xFF, 0xFF, // @0x50
+       0xFF, 0xFF, 0xFF, 0xFF, // @0x54: Macronix parameter table end
+};
+
+#endif
+#endif
+
+static unsigned int spi_write_256_chunksize = 256;
+
+static int dummy_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                                 unsigned int readcnt,
+                                 const unsigned char *writearr,
+                                 unsigned char *readarr);
+static int dummy_spi_write_256(struct flashctx *flash, uint8_t *buf,
+                              unsigned int start, unsigned int len);
+static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val,
+                             chipaddr addr);
+static void dummy_chip_writew(const struct flashctx *flash, uint16_t val,
+                             chipaddr addr);
+static void dummy_chip_writel(const struct flashctx *flash, uint32_t val,
+                             chipaddr addr);
+static void dummy_chip_writen(const struct flashctx *flash, uint8_t *buf,
+                             chipaddr addr, size_t len);
+static uint8_t dummy_chip_readb(const struct flashctx *flash,
+                               const chipaddr addr);
+static uint16_t dummy_chip_readw(const struct flashctx *flash,
+                                const chipaddr addr);
+static uint32_t dummy_chip_readl(const struct flashctx *flash,
+                                const chipaddr addr);
+static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf,
+                            const chipaddr addr, size_t len);
+
+static const struct spi_programmer spi_programmer_dummyflasher = {
+       .type           = SPI_CONTROLLER_DUMMY,
+       .max_data_read  = MAX_DATA_READ_UNLIMITED,
+       .max_data_write = MAX_DATA_UNSPECIFIED,
+       .command        = dummy_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = default_spi_read,
+       .write_256      = dummy_spi_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+static const struct par_programmer par_programmer_dummy = {
+               .chip_readb             = dummy_chip_readb,
+               .chip_readw             = dummy_chip_readw,
+               .chip_readl             = dummy_chip_readl,
+               .chip_readn             = dummy_chip_readn,
+               .chip_writeb            = dummy_chip_writeb,
+               .chip_writew            = dummy_chip_writew,
+               .chip_writel            = dummy_chip_writel,
+               .chip_writen            = dummy_chip_writen,
+};
+
+enum chipbustype dummy_buses_supported = BUS_NONE;
+
+static int dummy_shutdown(void *data)
+{
+       msg_pspew("%s\n", __func__);
+#if EMULATE_CHIP
+       if (emu_chip != EMULATE_NONE) {
+               if (emu_persistent_image) {
+                       msg_pdbg("Writing %s\n", emu_persistent_image);
+                       write_buf_to_file(flashchip_contents, emu_chip_size,
+                                         emu_persistent_image);
+               }
+               free(flashchip_contents);
+       }
+#endif
+       return 0;
+}
+
+int dummy_init(void)
+{
+       char *bustext = NULL;
+       char *tmp = NULL;
+       int i;
+#if EMULATE_SPI_CHIP
+       char *status = NULL;
+#endif
+#if EMULATE_CHIP
+       struct stat image_stat;
+#endif
+
+       msg_pspew("%s\n", __func__);
+
+       bustext = extract_programmer_param("bus");
+       msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
+       if (!bustext)
+               bustext = strdup("parallel+lpc+fwh+spi");
+       /* Convert the parameters to lowercase. */
+       tolower_string(bustext);
+
+       dummy_buses_supported = BUS_NONE;
+       if (strstr(bustext, "parallel")) {
+               dummy_buses_supported |= BUS_PARALLEL;
+               msg_pdbg("Enabling support for %s flash.\n", "parallel");
+       }
+       if (strstr(bustext, "lpc")) {
+               dummy_buses_supported |= BUS_LPC;
+               msg_pdbg("Enabling support for %s flash.\n", "LPC");
+       }
+       if (strstr(bustext, "fwh")) {
+               dummy_buses_supported |= BUS_FWH;
+               msg_pdbg("Enabling support for %s flash.\n", "FWH");
+       }
+       if (strstr(bustext, "spi")) {
+               dummy_buses_supported |= BUS_SPI;
+               msg_pdbg("Enabling support for %s flash.\n", "SPI");
+       }
+       if (dummy_buses_supported == BUS_NONE)
+               msg_pdbg("Support for all flash bus types disabled.\n");
+       free(bustext);
+
+       tmp = extract_programmer_param("spi_write_256_chunksize");
+       if (tmp) {
+               spi_write_256_chunksize = atoi(tmp);
+               free(tmp);
+               if (spi_write_256_chunksize < 1) {
+                       msg_perr("invalid spi_write_256_chunksize\n");
+                       return 1;
+               }
+       }
+
+       tmp = extract_programmer_param("spi_blacklist");
+       if (tmp) {
+               i = strlen(tmp);
+               if (!strncmp(tmp, "0x", 2)) {
+                       i -= 2;
+                       memmove(tmp, tmp + 2, i + 1);
+               }
+               if ((i > 512) || (i % 2)) {
+                       msg_perr("Invalid SPI command blacklist length\n");
+                       free(tmp);
+                       return 1;
+               }
+               spi_blacklist_size = i / 2;
+               for (i = 0; i < spi_blacklist_size * 2; i++) {
+                       if (!isxdigit((unsigned char)tmp[i])) {
+                               msg_perr("Invalid char \"%c\" in SPI command "
+                                        "blacklist\n", tmp[i]);
+                               free(tmp);
+                               return 1;
+                       }
+               }
+               for (i = 0; i < spi_blacklist_size; i++) {
+                       unsigned int tmp2;
+                       /* SCNx8 is apparently not supported by MSVC (and thus
+                        * MinGW), so work around it with an extra variable
+                        */
+                       sscanf(tmp + i * 2, "%2x", &tmp2);
+                       spi_blacklist[i] = (uint8_t)tmp2;
+               }
+               msg_pdbg("SPI blacklist is ");
+               for (i = 0; i < spi_blacklist_size; i++)
+                       msg_pdbg("%02x ", spi_blacklist[i]);
+               msg_pdbg(", size %i\n", spi_blacklist_size);
+       }
+       free(tmp);
+
+       tmp = extract_programmer_param("spi_ignorelist");
+       if (tmp) {
+               i = strlen(tmp);
+               if (!strncmp(tmp, "0x", 2)) {
+                       i -= 2;
+                       memmove(tmp, tmp + 2, i + 1);
+               }
+               if ((i > 512) || (i % 2)) {
+                       msg_perr("Invalid SPI command ignorelist length\n");
+                       free(tmp);
+                       return 1;
+               }
+               spi_ignorelist_size = i / 2;
+               for (i = 0; i < spi_ignorelist_size * 2; i++) {
+                       if (!isxdigit((unsigned char)tmp[i])) {
+                               msg_perr("Invalid char \"%c\" in SPI command "
+                                        "ignorelist\n", tmp[i]);
+                               free(tmp);
+                               return 1;
+                       }
+               }
+               for (i = 0; i < spi_ignorelist_size; i++) {
+                       unsigned int tmp2;
+                       /* SCNx8 is apparently not supported by MSVC (and thus
+                        * MinGW), so work around it with an extra variable
+                        */
+                       sscanf(tmp + i * 2, "%2x", &tmp2);
+                       spi_ignorelist[i] = (uint8_t)tmp2;
+               }
+               msg_pdbg("SPI ignorelist is ");
+               for (i = 0; i < spi_ignorelist_size; i++)
+                       msg_pdbg("%02x ", spi_ignorelist[i]);
+               msg_pdbg(", size %i\n", spi_ignorelist_size);
+       }
+       free(tmp);
+
+#if EMULATE_CHIP
+       tmp = extract_programmer_param("emulate");
+       if (!tmp) {
+               msg_pdbg("Not emulating any flash chip.\n");
+               /* Nothing else to do. */
+               goto dummy_init_out;
+       }
+#if EMULATE_SPI_CHIP
+       if (!strcmp(tmp, "M25P10.RES")) {
+               emu_chip = EMULATE_ST_M25P10_RES;
+               emu_chip_size = 128 * 1024;
+               emu_max_byteprogram_size = 128;
+               emu_max_aai_size = 0;
+               emu_jedec_se_size = 0;
+               emu_jedec_be_52_size = 0;
+               emu_jedec_be_d8_size = 32 * 1024;
+               emu_jedec_ce_60_size = 0;
+               emu_jedec_ce_c7_size = emu_chip_size;
+               msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
+                        "write)\n");
+       }
+       if (!strcmp(tmp, "SST25VF040.REMS")) {
+               emu_chip = EMULATE_SST_SST25VF040_REMS;
+               emu_chip_size = 512 * 1024;
+               emu_max_byteprogram_size = 1;
+               emu_max_aai_size = 0;
+               emu_jedec_se_size = 4 * 1024;
+               emu_jedec_be_52_size = 32 * 1024;
+               emu_jedec_be_d8_size = 0;
+               emu_jedec_ce_60_size = emu_chip_size;
+               emu_jedec_ce_c7_size = 0;
+               msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
+                        "byte write)\n");
+       }
+       if (!strcmp(tmp, "SST25VF032B")) {
+               emu_chip = EMULATE_SST_SST25VF032B;
+               emu_chip_size = 4 * 1024 * 1024;
+               emu_max_byteprogram_size = 1;
+               emu_max_aai_size = 2;
+               emu_jedec_se_size = 4 * 1024;
+               emu_jedec_be_52_size = 32 * 1024;
+               emu_jedec_be_d8_size = 64 * 1024;
+               emu_jedec_ce_60_size = emu_chip_size;
+               emu_jedec_ce_c7_size = emu_chip_size;
+               msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
+                        "write)\n");
+       }
+       if (!strcmp(tmp, "MX25L6436")) {
+               emu_chip = EMULATE_MACRONIX_MX25L6436;
+               emu_chip_size = 8 * 1024 * 1024;
+               emu_max_byteprogram_size = 256;
+               emu_max_aai_size = 0;
+               emu_jedec_se_size = 4 * 1024;
+               emu_jedec_be_52_size = 32 * 1024;
+               emu_jedec_be_d8_size = 64 * 1024;
+               emu_jedec_ce_60_size = emu_chip_size;
+               emu_jedec_ce_c7_size = emu_chip_size;
+               msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
+                        "SFDP)\n");
+       }
+#endif
+       if (emu_chip == EMULATE_NONE) {
+               msg_perr("Invalid chip specified for emulation: %s\n", tmp);
+               free(tmp);
+               return 1;
+       }
+       free(tmp);
+       flashchip_contents = malloc(emu_chip_size);
+       if (!flashchip_contents) {
+               msg_perr("Out of memory!\n");
+               return 1;
+       }
+
+#ifdef EMULATE_SPI_CHIP
+       status = extract_programmer_param("spi_status");
+       if (status) {
+               char *endptr;
+               errno = 0;
+               emu_status = strtoul(status, &endptr, 0);
+               free(status);
+               if (errno != 0 || status == endptr) {
+                       msg_perr("Error: initial status register specified, "
+                                "but the value could not be converted.\n");
+                       return 1;
+               }
+               msg_pdbg("Initial status register is set to 0x%02x.\n",
+                        emu_status);
+       }
+#endif
+
+       msg_pdbg("Filling fake flash chip with 0xff, size %i\n", emu_chip_size);
+       memset(flashchip_contents, 0xff, emu_chip_size);
+
+       emu_persistent_image = extract_programmer_param("image");
+       if (!emu_persistent_image) {
+               /* Nothing else to do. */
+               goto dummy_init_out;
+       }
+       if (!stat(emu_persistent_image, &image_stat)) {
+               msg_pdbg("Found persistent image %s, size %li ",
+                        emu_persistent_image, (long)image_stat.st_size);
+               if (image_stat.st_size == emu_chip_size) {
+                       msg_pdbg("matches.\n");
+                       msg_pdbg("Reading %s\n", emu_persistent_image);
+                       read_buf_from_file(flashchip_contents, emu_chip_size,
+                                          emu_persistent_image);
+               } else {
+                       msg_pdbg("doesn't match.\n");
+               }
+       }
+#endif
+
+dummy_init_out:
+       if (register_shutdown(dummy_shutdown, NULL)) {
+               free(flashchip_contents);
+               return 1;
+       }
+       if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
+               register_par_programmer(&par_programmer_dummy,
+                                       dummy_buses_supported &
+                                               (BUS_PARALLEL | BUS_LPC |
+                                                BUS_FWH));
+       if (dummy_buses_supported & BUS_SPI)
+               register_spi_programmer(&spi_programmer_dummyflasher);
+
+       return 0;
+}
+
+void *dummy_map(const char *descr, unsigned long phys_addr, size_t len)
+{
+       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)
+{
+       msg_pspew("%s: Unmapping 0x%lx bytes at %p\n",
+                 __func__, (unsigned long)len, virt_addr);
+}
+
+static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val,
+                             chipaddr addr)
+{
+       msg_pspew("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val);
+}
+
+static void dummy_chip_writew(const struct flashctx *flash, uint16_t val,
+                             chipaddr addr)
+{
+       msg_pspew("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val);
+}
+
+static void dummy_chip_writel(const struct flashctx *flash, uint32_t val,
+                             chipaddr addr)
+{
+       msg_pspew("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val);
+}
+
+static void dummy_chip_writen(const struct flashctx *flash, uint8_t *buf,
+                             chipaddr addr, size_t len)
+{
+       size_t i;
+       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)
+                       msg_pspew("\n");
+               msg_pspew("%02x ", buf[i]);
+       }
+}
+
+static uint8_t dummy_chip_readb(const struct flashctx *flash,
+                               const chipaddr addr)
+{
+       msg_pspew("%s:  addr=0x%lx, returning 0xff\n", __func__, addr);
+       return 0xff;
+}
+
+static uint16_t dummy_chip_readw(const struct flashctx *flash,
+                                const chipaddr addr)
+{
+       msg_pspew("%s:  addr=0x%lx, returning 0xffff\n", __func__, addr);
+       return 0xffff;
+}
+
+static uint32_t dummy_chip_readl(const struct flashctx *flash,
+                                const chipaddr addr)
+{
+       msg_pspew("%s:  addr=0x%lx, returning 0xffffffff\n", __func__, addr);
+       return 0xffffffff;
+}
+
+static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf,
+                            const chipaddr addr, size_t 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;
+}
+
+#if EMULATE_SPI_CHIP
+static int emulate_spi_chip_response(unsigned int writecnt,
+                                    unsigned int readcnt,
+                                    const unsigned char *writearr,
+                                    unsigned char *readarr)
+{
+       unsigned int offs, i, toread;
+       static int unsigned aai_offs;
+
+       if (writecnt == 0) {
+               msg_perr("No command sent to the chip!\n");
+               return 1;
+       }
+       /* spi_blacklist has precedence over spi_ignorelist. */
+       for (i = 0; i < spi_blacklist_size; i++) {
+               if (writearr[0] == spi_blacklist[i]) {
+                       msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
+                                spi_blacklist[i]);
+                       return SPI_INVALID_OPCODE;
+               }
+       }
+       for (i = 0; i < spi_ignorelist_size; i++) {
+               if (writearr[0] == spi_ignorelist[i]) {
+                       msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
+                                spi_ignorelist[i]);
+                       /* Return success because the command does not fail,
+                        * it is simply ignored.
+                        */
+                       return 0;
+               }
+       }
+
+       if (emu_max_aai_size && (emu_status & SPI_SR_AAI)) {
+               if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
+                   writearr[0] != JEDEC_WRDI &&
+                   writearr[0] != JEDEC_RDSR) {
+                       msg_perr("Forbidden opcode (0x%02x) attempted during "
+                                "AAI sequence!\n", writearr[0]);
+                       return 0;
+               }
+       }
+
+       switch (writearr[0]) {
+       case JEDEC_RES:
+               if (emu_chip != EMULATE_ST_M25P10_RES)
+                       break;
+               /* Respond with ST_M25P10_RES. */
+               if (readcnt > 0)
+                       readarr[0] = 0x10;
+               break;
+       case JEDEC_REMS:
+               if (emu_chip != EMULATE_SST_SST25VF040_REMS)
+                       break;
+               /* Respond with SST_SST25VF040_REMS. */
+               if (readcnt > 0)
+                       readarr[0] = 0xbf;
+               if (readcnt > 1)
+                       readarr[1] = 0x44;
+               break;
+       case JEDEC_RDID:
+               switch (emu_chip) {
+               case EMULATE_SST_SST25VF032B:
+                       if (readcnt > 0)
+                               readarr[0] = 0xbf;
+                       if (readcnt > 1)
+                               readarr[1] = 0x25;
+                       if (readcnt > 2)
+                               readarr[2] = 0x4a;
+                       break;
+               case EMULATE_MACRONIX_MX25L6436:
+                       if (readcnt > 0)
+                               readarr[0] = 0xc2;
+                       if (readcnt > 1)
+                               readarr[1] = 0x20;
+                       if (readcnt > 2)
+                               readarr[2] = 0x17;
+                       break;
+               default: /* ignore */
+                       break;
+               }
+               break;
+       case JEDEC_RDSR:
+               memset(readarr, emu_status, readcnt);
+               break;
+       /* FIXME: this should be chip-specific. */
+       case JEDEC_EWSR:
+       case JEDEC_WREN:
+               emu_status |= SPI_SR_WEL;
+               break;
+       case JEDEC_WRSR:
+               if (!(emu_status & SPI_SR_WEL)) {
+                       msg_perr("WRSR attempted, but WEL is 0!\n");
+                       break;
+               }
+               /* FIXME: add some reasonable simulation of the busy flag */
+               emu_status = writearr[1] & ~SPI_SR_WIP;
+               msg_pdbg2("WRSR wrote 0x%02x.\n", emu_status);
+               break;
+       case JEDEC_READ:
+               offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+               /* Truncate to emu_chip_size. */
+               offs %= emu_chip_size;
+               if (readcnt > 0)
+                       memcpy(readarr, flashchip_contents + offs, readcnt);
+               break;
+       case JEDEC_BYTE_PROGRAM:
+               offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+               /* Truncate to emu_chip_size. */
+               offs %= emu_chip_size;
+               if (writecnt < 5) {
+                       msg_perr("BYTE PROGRAM size too short!\n");
+                       return 1;
+               }
+               if (writecnt - 4 > emu_max_byteprogram_size) {
+                       msg_perr("Max BYTE PROGRAM size exceeded!\n");
+                       return 1;
+               }
+               memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
+               break;
+       case JEDEC_AAI_WORD_PROGRAM:
+               if (!emu_max_aai_size)
+                       break;
+               if (!(emu_status & SPI_SR_AAI)) {
+                       if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
+                               msg_perr("Initial AAI WORD PROGRAM size too "
+                                        "short!\n");
+                               return 1;
+                       }
+                       if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
+                               msg_perr("Initial AAI WORD PROGRAM size too "
+                                        "long!\n");
+                               return 1;
+                       }
+                       emu_status |= SPI_SR_AAI;
+                       aai_offs = writearr[1] << 16 | writearr[2] << 8 |
+                                  writearr[3];
+                       /* Truncate to emu_chip_size. */
+                       aai_offs %= emu_chip_size;
+                       memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
+                       aai_offs += 2;
+               } else {
+                       if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
+                               msg_perr("Continuation AAI WORD PROGRAM size "
+                                        "too short!\n");
+                               return 1;
+                       }
+                       if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
+                               msg_perr("Continuation AAI WORD PROGRAM size "
+                                        "too long!\n");
+                               return 1;
+                       }
+                       memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
+                       aai_offs += 2;
+               }
+               break;
+       case JEDEC_WRDI:
+               if (emu_max_aai_size)
+                       emu_status &= ~SPI_SR_AAI;
+               break;
+       case JEDEC_SE:
+               if (!emu_jedec_se_size)
+                       break;
+               if (writecnt != JEDEC_SE_OUTSIZE) {
+                       msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
+                       return 1;
+               }
+               if (readcnt != JEDEC_SE_INSIZE) {
+                       msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
+                       return 1;
+               }
+               offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+               if (offs & (emu_jedec_se_size - 1))
+                       msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
+               offs &= ~(emu_jedec_se_size - 1);
+               memset(flashchip_contents + offs, 0xff, emu_jedec_se_size);
+               break;
+       case JEDEC_BE_52:
+               if (!emu_jedec_be_52_size)
+                       break;
+               if (writecnt != JEDEC_BE_52_OUTSIZE) {
+                       msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
+                       return 1;
+               }
+               if (readcnt != JEDEC_BE_52_INSIZE) {
+                       msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
+                       return 1;
+               }
+               offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+               if (offs & (emu_jedec_be_52_size - 1))
+                       msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
+               offs &= ~(emu_jedec_be_52_size - 1);
+               memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size);
+               break;
+       case JEDEC_BE_D8:
+               if (!emu_jedec_be_d8_size)
+                       break;
+               if (writecnt != JEDEC_BE_D8_OUTSIZE) {
+                       msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
+                       return 1;
+               }
+               if (readcnt != JEDEC_BE_D8_INSIZE) {
+                       msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
+                       return 1;
+               }
+               offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+               if (offs & (emu_jedec_be_d8_size - 1))
+                       msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
+               offs &= ~(emu_jedec_be_d8_size - 1);
+               memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size);
+               break;
+       case JEDEC_CE_60:
+               if (!emu_jedec_ce_60_size)
+                       break;
+               if (writecnt != JEDEC_CE_60_OUTSIZE) {
+                       msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
+                       return 1;
+               }
+               if (readcnt != JEDEC_CE_60_INSIZE) {
+                       msg_perr("CHIP ERASE 0x60 insize invalid!\n");
+                       return 1;
+               }
+               /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
+               /* emu_jedec_ce_60_size is emu_chip_size. */
+               memset(flashchip_contents, 0xff, emu_jedec_ce_60_size);
+               break;
+       case JEDEC_CE_C7:
+               if (!emu_jedec_ce_c7_size)
+                       break;
+               if (writecnt != JEDEC_CE_C7_OUTSIZE) {
+                       msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
+                       return 1;
+               }
+               if (readcnt != JEDEC_CE_C7_INSIZE) {
+                       msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
+                       return 1;
+               }
+               /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
+               /* emu_jedec_ce_c7_size is emu_chip_size. */
+               memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size);
+               break;
+       case JEDEC_SFDP:
+               if (emu_chip != EMULATE_MACRONIX_MX25L6436)
+                       break;
+               if (writecnt < 4)
+                       break;
+               offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+
+               /* SFDP expects one dummy byte after the address. */
+               if (writecnt == 4) {
+                       /* The dummy byte was not written, make sure it is read instead.
+                        * Shifting and shortening the read array does achieve this goal.
+                        */
+                       readarr++;
+                       readcnt--;
+               } else {
+                       /* The response is shifted if more than 5 bytes are written, because SFDP data is
+                        * already shifted out by the chip while those superfluous bytes are written. */
+                       offs += writecnt - 5;
+               }
+
+               /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
+                * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
+                * This is a reasonable implementation choice in hardware because it saves a few gates. */
+               if (offs >= sizeof(sfdp_table)) {
+                       msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
+                                "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
+                       offs %= sizeof(sfdp_table);
+               }
+               toread = min(sizeof(sfdp_table) - offs, readcnt);
+               memcpy(readarr, sfdp_table + offs, toread);
+               if (toread < readcnt)
+                       msg_pdbg("Crossing the SFDP table boundary in a single "
+                                "continuous chunk produces undefined results "
+                                "after that point.\n");
+               break;
+       default:
+               /* No special response. */
+               break;
+       }
+       if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
+               emu_status &= ~SPI_SR_WEL;
+       return 0;
+}
+#endif
+
+static int dummy_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                                 unsigned int readcnt,
+                                 const unsigned char *writearr,
+                                 unsigned char *readarr)
+{
+       int i;
+
+       msg_pspew("%s:", __func__);
+
+       msg_pspew(" writing %u bytes:", writecnt);
+       for (i = 0; i < writecnt; i++)
+               msg_pspew(" 0x%02x", writearr[i]);
+
+       /* Response for unknown commands and missing chip is 0xff. */
+       memset(readarr, 0xff, readcnt);
+#if EMULATE_SPI_CHIP
+       switch (emu_chip) {
+       case EMULATE_ST_M25P10_RES:
+       case EMULATE_SST_SST25VF040_REMS:
+       case EMULATE_SST_SST25VF032B:
+       case EMULATE_MACRONIX_MX25L6436:
+               if (emulate_spi_chip_response(writecnt, readcnt, writearr,
+                                             readarr)) {
+                       msg_pdbg("Invalid command sent to flash chip!\n");
+                       return 1;
+               }
+               break;
+       default:
+               break;
+       }
+#endif
+       msg_pspew(" reading %u bytes:", readcnt);
+       for (i = 0; i < readcnt; i++)
+               msg_pspew(" 0x%02x", readarr[i]);
+       msg_pspew("\n");
+       return 0;
+}
+
+static int dummy_spi_write_256(struct flashctx *flash, uint8_t *buf,
+                              unsigned int start, unsigned int len)
+{
+       return spi_write_chunked(flash, buf, start, len,
+                                spi_write_256_chunksize);
+}
diff --git a/en29lv640b.c b/en29lv640b.c
new file mode 100644 (file)
index 0000000..0dff2d1
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2012 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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"
+#include "chipdrivers.h"
+
+/*
+ * 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.
+ */
+
+/* chunksize is 1 */
+int write_en29lv640b(struct flashctx *flash, uint8_t *src, unsigned int start,
+                    unsigned int len)
+{
+       int i;
+       chipaddr bios = flash->virtual_memory;
+       chipaddr dst = flash->virtual_memory + start;
+
+       for (i = 0; i < len; i += 2) {
+               chip_writeb(flash, 0xAA, bios + 0xAAA);
+               chip_writeb(flash, 0x55, bios + 0x555);
+               chip_writeb(flash, 0xA0, bios + 0xAAA);
+
+               /* Transfer data from source to destination. */
+               chip_writew(flash, (*src) | ((*(src + 1)) << 8 ), dst);
+               toggle_ready_jedec(flash, dst);
+#if 0
+               /* We only want to print something in the error case. */
+               msg_cerr("Value in the flash at address 0x%lx = %#x, want %#x\n",
+                        (dst - bios), chip_readb(flash, dst), *src);
+#endif
+               dst += 2;
+               src += 2;
+       }
+
+       /* FIXME: Ignore errors for now. */
+       return 0;
+}
+
+int probe_en29lv640b(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint16_t id1, id2;
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x90, bios + 0xAAA);
+
+       programmer_delay(10);
+
+       id1 = chip_readb(flash, bios + 0x200);
+       id1 |= (chip_readb(flash, bios) << 8);
+
+       id2 = chip_readb(flash, bios + 0x02);
+
+       chip_writeb(flash, 0xF0, bios + 0xAAA);
+
+       programmer_delay(10);
+
+       msg_cdbg("%s: id1 0x%04x, id2 0x%04x\n", __func__, id1, id2);
+
+       if (id1 == flash->manufacture_id && id2 == flash->model_id)
+               return 1;
+
+       return 0;
+}
+
+int erase_en29lv640b(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x80, bios + 0xAAA);
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x10, bios + 0xAAA);
+
+       programmer_delay(10);
+       toggle_ready_jedec(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int block_erase_en29lv640b(struct flashctx *flash, unsigned int start,
+                          unsigned int len)
+{
+       chipaddr bios = flash->virtual_memory;
+       chipaddr dst = bios + start;
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x80, bios + 0xAAA);
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x30, dst);
+
+       programmer_delay(10);
+       toggle_ready_jedec(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int block_erase_chip_en29lv640b(struct flashctx *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_en29lv640b(flash);
+}
diff --git a/flash.h b/flash.h
new file mode 100644 (file)
index 0000000..b41c281
--- /dev/null
+++ b/flash.h
@@ -0,0 +1,324 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
+ * Copyright (C) 2005-2009 coresystems GmbH
+ * Copyright (C) 2006-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
+ */
+
+#ifndef __FLASH_H__
+#define __FLASH_H__ 1
+
+#include <stdint.h>
+#include <stddef.h>
+#ifdef _WIN32
+#include <windows.h>
+#undef min
+#undef max
+#endif
+
+#define ERROR_PTR ((void*)-1)
+
+/* Error codes */
+#define ERROR_OOM      -100
+#define TIMEOUT_ERROR  -101
+
+typedef unsigned long chipaddr;
+
+int register_shutdown(int (*function) (void *data), void *data);
+void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
+                                 size_t len);
+void programmer_unmap_flash_region(void *virt_addr, size_t len);
+void programmer_delay(int usecs);
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+enum chipbustype {
+       BUS_NONE        = 0,
+       BUS_PARALLEL    = 1 << 0,
+       BUS_LPC         = 1 << 1,
+       BUS_FWH         = 1 << 2,
+       BUS_SPI         = 1 << 3,
+       BUS_PROG        = 1 << 4,
+       BUS_NONSPI      = BUS_PARALLEL | BUS_LPC | BUS_FWH,
+};
+
+/*
+ * 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?
+ * Atmel AT25FS010 has 6 different functions.
+ */
+#define NUM_ERASEFUNCTIONS 6
+
+#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_RESET_MASK     (FEATURE_LONG_RESET | FEATURE_SHORT_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)
+#define FEATURE_WRSR_EWSR      (1 << 6)
+#define FEATURE_WRSR_WREN      (1 << 7)
+#define FEATURE_OTP            (1 << 8)
+#define FEATURE_WRSR_EITHER    (FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
+
+struct flashctx;
+
+struct flashchip {
+       const char *vendor;
+       const char *name;
+
+       enum chipbustype bustype;
+
+       /*
+        * With 32bit manufacture_id and model_id we can cover IDs up to
+        * (including) the 4th bank of JEDEC JEP106W Standard Manufacturer's
+        * Identification code.
+        */
+       uint32_t manufacture_id;
+       uint32_t model_id;
+
+       /* Total chip size in kilobytes */
+       unsigned int total_size;
+       /* Chip page size in bytes */
+       unsigned int page_size;
+       int feature_bits;
+
+       /*
+        * Indicate if flashrom has been tested with this flash chip and if
+        * everything worked correctly.
+        */
+       uint32_t tested;
+
+       int (*probe) (struct flashctx *flash);
+
+       /* Delay after "enter/exit ID mode" commands in microseconds.
+        * NB: negative values have special meanings, see TIMING_* below.
+        */
+       signed int probe_timing;
+
+       /*
+        * Erase blocks and associated erase function. Any chip erase function
+        * is stored as chip-sized virtual block together with said function.
+        * The first one that fits will be chosen. There is currently no way to
+        * influence that behaviour. For testing just comment out the other
+        * elements or set the function pointer to NULL.
+        */
+       struct block_eraser {
+               struct eraseblock{
+                       unsigned int size; /* Eraseblock size in bytes */
+                       unsigned int count; /* Number of contiguous blocks with that size */
+               } eraseblocks[NUM_ERASEREGIONS];
+               /* a block_erase function should try to erase one block of size
+                * 'blocklen' at address 'blockaddr' and return 0 on success. */
+               int (*block_erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+       } block_erasers[NUM_ERASEFUNCTIONS];
+
+       int (*printlock) (struct flashctx *flash);
+       int (*unlock) (struct flashctx *flash);
+       int (*write) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       struct voltage {
+               uint16_t min;
+               uint16_t max;
+       } voltage;
+};
+
+/* struct flashctx must always contain struct flashchip at the beginning. */
+struct flashctx {
+       const char *vendor;
+       const char *name;
+       enum chipbustype bustype;
+       uint32_t manufacture_id;
+       uint32_t model_id;
+       int total_size;
+       int page_size;
+       int feature_bits;
+       uint32_t tested;
+       int (*probe) (struct flashctx *flash);
+       int probe_timing;
+       struct block_eraser block_erasers[NUM_ERASEFUNCTIONS];
+       int (*printlock) (struct flashctx *flash);
+       int (*unlock) (struct flashctx *flash);
+       int (*write) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       struct voltage voltage;
+       /* struct flashchip ends here. */
+       
+       chipaddr virtual_memory;
+       /* Some flash devices have an additional register space. */
+       chipaddr virtual_registers;
+       struct registered_programmer *pgm;
+};
+
+typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+
+#define TEST_UNTESTED  0
+
+#define TEST_OK_PROBE  (1 << 0)
+#define TEST_OK_READ   (1 << 1)
+#define TEST_OK_ERASE  (1 << 2)
+#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
+
+#define TEST_BAD_PROBE (1 << 4)
+#define TEST_BAD_READ  (1 << 5)
+#define TEST_BAD_ERASE (1 << 6)
+#define TEST_BAD_WRITE (1 << 7)
+#define TEST_BAD_PREW  (TEST_BAD_PROBE | TEST_BAD_READ | TEST_BAD_ERASE | TEST_BAD_WRITE)
+#define TEST_BAD_MASK  0xf0
+
+/* Timing used in probe routines. ZERO is -2 to differentiate between an unset
+ * field and zero delay.
+ * 
+ * SPI devices will always have zero delay and ignore this field.
+ */
+#define TIMING_FIXME   -1
+/* this is intentionally same value as fixme */
+#define TIMING_IGNORED -1
+#define TIMING_ZERO    -2
+
+extern const struct flashchip flashchips[];
+
+void chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
+void chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
+void chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr);
+void chip_writen(const struct flashctx *flash, uint8_t *buf, chipaddr addr, size_t len);
+uint8_t chip_readb(const struct flashctx *flash, const chipaddr addr);
+uint16_t chip_readw(const struct flashctx *flash, const chipaddr addr);
+uint32_t chip_readl(const struct flashctx *flash, const chipaddr addr);
+void chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
+
+/* print.c */
+char *flashbuses_to_text(enum chipbustype bustype);
+void print_supported(void);
+void print_supported_wiki(void);
+
+/* flashrom.c */
+enum write_granularity {
+       write_gran_1bit,
+       write_gran_1byte,
+       write_gran_256bytes,
+};
+extern int verbose_screen;
+extern int verbose_logfile;
+extern const char flashrom_version[];
+extern char *chip_to_probe;
+void map_flash_registers(struct flashctx *flash);
+int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int erase_flash(struct flashctx *flash);
+int probe_flash(struct registered_programmer *pgm, int startchip, struct flashctx *fill_flash, int force);
+int read_flash_to_file(struct flashctx *flash, const char *filename);
+int min(int a, int b);
+int max(int a, int b);
+void tolower_string(char *str);
+char *extract_param(char **haystack, const char *needle, const char *delim);
+int verify_range(struct flashctx *flash, uint8_t *cmpbuf, unsigned int start, unsigned int len, const char *message);
+int need_erase(uint8_t *have, uint8_t *want, unsigned int len, enum write_granularity gran);
+char *strcat_realloc(char *dest, const char *src);
+void print_version(void);
+void print_buildinfo(void);
+void print_banner(void);
+void list_programmers_linebreak(int startcol, int cols, int paren);
+int selfcheck(void);
+int doit(struct flashctx *flash, int force, const char *filename, int read_it, int write_it, int erase_it, int verify_it);
+int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename);
+int write_buf_to_file(unsigned char *buf, unsigned long size, const char *filename);
+
+enum test_state {
+       OK = 0,
+       NT = 1, /* Not tested */
+       BAD
+};
+
+/* Something happened that shouldn't happen, but we can go on. */
+#define ERROR_NONFATAL 0x100
+
+/* Something happened that shouldn't happen, we'll abort. */
+#define ERROR_FATAL -0xee
+#define ERROR_FLASHROM_BUG -200
+/* We reached one of the hardcoded limits of flashrom. This can be fixed by
+ * increasing the limit of a compile-time allocation or by switching to dynamic
+ * allocation.
+ * Note: If this warning is triggered, check first for runaway registrations.
+ */
+#define ERROR_FLASHROM_LIMIT -201
+
+/* cli_output.c */
+#ifndef STANDALONE
+int open_logfile(const char * const filename);
+int close_logfile(void);
+void start_logging(void);
+#endif
+enum msglevel {
+       MSG_ERROR       = 0,
+       MSG_INFO        = 1,
+       MSG_DEBUG       = 2,
+       MSG_DEBUG2      = 3,
+       MSG_SPEW        = 4,
+};
+/* Let gcc and clang check for correct printf-style format strings. */
+int print(enum msglevel level, const char *fmt, ...) __attribute__((format(printf, 2, 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_gdbg2(...) print(MSG_DEBUG2, __VA_ARGS__)  /* general debug2 */
+#define msg_pdbg2(...) print(MSG_DEBUG2, __VA_ARGS__)  /* programmer debug2 */
+#define msg_cdbg2(...) print(MSG_DEBUG2, __VA_ARGS__)  /* chip debug2 */
+#define msg_gspew(...) print(MSG_SPEW, __VA_ARGS__)    /* general debug spew  */
+#define msg_pspew(...) print(MSG_SPEW, __VA_ARGS__)    /* programmer debug spew  */
+#define msg_cspew(...) print(MSG_SPEW, __VA_ARGS__)    /* chip debug spew  */
+
+/* layout.c */
+int register_include_arg(char *name);
+int process_include_args(void);
+int read_romlayout(char *name);
+int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents);
+
+/* spi.c */
+struct spi_command {
+       unsigned int writecnt;
+       unsigned int readcnt;
+       const unsigned char *writearr;
+       unsigned char *readarr;
+};
+int spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
+int spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds);
+uint32_t spi_get_valid_read_addr(struct flashctx *flash);
+
+enum chipbustype get_buses_supported(void);
+#endif                         /* !__FLASH_H__ */
diff --git a/flashchips.c b/flashchips.c
new file mode 100644 (file)
index 0000000..b09727c
--- /dev/null
@@ -0,0 +1,9589 @@
+/*
+ * 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 <stepan@openbios.org>
+ * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+#include "flashchips.h"
+#include "chipdrivers.h"
+
+/**
+ * List of supported flash chips.
+ *
+ * Please keep the list sorted by vendor name and chip name, so that
+ * the output of 'flashrom -L' is alphabetically sorted.
+ */
+const struct flashchip flashchips[] = {
+
+       /*
+        * .vendor              = Vendor name
+        * .name                = Chip name
+        * .bustype             = Supported flash bus types (Parallel, LPC...)
+        * .manufacture_id      = Manufacturer chip ID
+        * .model_id            = Model chip ID
+        * .total_size          = Total size in (binary) kbytes
+        * .page_size           = Page or eraseblock(?) size in bytes
+        * .tested              = Test status
+        * .probe               = Probe function
+        * .probe_timing        = Probe function delay
+        * .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
+        * .voltage             = Voltage range in millivolt
+        */
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29F010A/B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29F010B,        /* Same as Am29F010A */
+               .total_size     = 128,
+               .page_size      = 16 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PRE,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29F002(N)BB",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29F002BB,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_SHORT_RESET | FEATURE_ADDR_2AA,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29F002(N)BT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29F002BT,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_EITHER_RESET | FEATURE_ADDR_2AA,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29F016D",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29F016D,
+               .total_size     = 2 * 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29F040B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29F040B,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29F080B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29F080B,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV001BB",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV001BB,
+               .total_size     = 128,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {8 * 1024, 1},
+                                       {4 * 1024, 2},
+                                       {16 * 1024, 7},
+                               },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* 3.0-3.6V for type -45R, others 2.7-3.6V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV001BT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV001BT,
+               .total_size     = 128,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {16 * 1024, 7},
+                                       {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,
+               .voltage        = {3000, 3600}, /* 3.0-3.6V for type -45R, others 2.7-3.6V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV002BB",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV002BB,
+               .total_size     = 256,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {3000, 3600}, /* 3.0-3.6V for type -55, others 2.7-3.6V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV002BT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV002BT,
+               .total_size     = 256,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {3000, 3600}, /* 3.0-3.6V for type -55, others 2.7-3.6V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV004BB",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV004BB,
+               .total_size     = 512,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV004BT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV004BT,
+               .total_size     = 512,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV008BB",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV008BB,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {16 * 1024, 1},
+                                       {8 * 1024, 2},
+                                       {32 * 1024, 1},
+                                       {64 * 1024, 15},
+                               },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {1024 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600} /* 3.0-3.6V for type -70R, others 2.7-3.6V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV008BT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV008BT,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024, /* unused */
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {64 * 1024, 15},
+                                       {32 * 1024, 1},
+                                       {8 * 1024, 2},
+                                       {16 * 1024, 1},
+                               },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {1024 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600} /* 3.0-3.6V for type -70R, others 2.7-3.6V */
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV040B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV040B,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {3000, 3600}, /* 3.0-3.6V for type -60R, others 2.7-3.6V*/
+       },
+
+       {
+               .vendor         = "AMD",
+               .name           = "Am29LV081B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMD_ID,
+               .model_id       = AMD_AM29LV080B,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, /* datasheet specifies address as don't care */
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {3000, 3600}, /* 3.0-3.6V for type -70R, others 2.7-3.6V */
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L05PT",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L05PT,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid4,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l05p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L05PU",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L05PU,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid4,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l05p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L10PT",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L10PT,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid4,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {64 * 1024, 1},
+                                       {32 * 1024, 1},
+                                       {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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l05p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L10PU",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L10PU,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .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, 1},
+                               },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l05p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L20PT",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L20PT,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid4,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l05p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L20PU",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L20PU,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .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, 3},
+                               },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l05p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       /* The A25L40P{T,U} chips are distinguished by their
+        * erase block layouts, but without any distinction in RDID.
+        * This inexplicable quirk was verified by Rudolf Marek
+        * and discussed on the flashrom mailing list on 2010-07-12.
+        */
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L40PT",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L40PT,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_spi_rdid4,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L40PU",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L40PU,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PR,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L80P",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L80P,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PRE,
+               .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, 15},
+                               },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {1024 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L16PT",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L16PT,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid4,
+               .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 = { {2048 * 1024, 1} },
+                               .block_erase = spi_block_erase_60,
+                       }, {
+                               .eraseblocks = { {2048 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L16PU",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = AMIC_A25L16PU,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PR,
+               .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, 31},
+                               },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {2048 * 1024, 1} },
+                               .block_erase = spi_block_erase_60,
+                       }, {
+                               .eraseblocks = { {2048 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L512",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25L512,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { { 4 * 1024, 16 } },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { { 64 * 1024, 1 } },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { { 64 * 1024, 1 } },
+                               .block_erase = spi_block_erase_c7,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L010",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25L010,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L020",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25L020,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L040",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25L040,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L080",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25L080,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L016",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25L016,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { { 4 * 1024, 512 } },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { { 64 * 1024, 32 } },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { { 2048 * 1024, 1 } },
+                               .block_erase = spi_block_erase_c7,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l40p,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25L032",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25L032,
+               .total_size     = 4096,
+               .page_size      = 256,
+               /* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { { 4 * 1024, 1024 } },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { { 64 * 1024, 64 } },
+                               .block_erase = spi_block_erase_52,
+                       }, {
+                               .eraseblocks = { { 64 * 1024, 64 } },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { { 4096 * 1024, 1 } },
+                               .block_erase = spi_block_erase_60,
+                       }, {
+                               .eraseblocks = { { 4096 * 1024, 1 } },
+                               .block_erase = spi_block_erase_c7,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25l032,
+               .unlock         = NULL, /* Two status reg bytes (read with 0x35 and 0x05) */
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A25LQ032",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A25LQ032,
+               .total_size     = 4096,
+               .page_size      = 256,
+               /* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { { 4 * 1024, 1024 } },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { { 64 * 1024, 64 } },
+                               .block_erase = spi_block_erase_52,
+                       }, {
+                               .eraseblocks = { { 64 * 1024, 64 } },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { { 4096 * 1024, 1 } },
+                               .block_erase = spi_block_erase_60,
+                       }, {
+                               .eraseblocks = { { 4096 * 1024, 1 } },
+                               .block_erase = spi_block_erase_c7,
+                       }                       
+               },
+               .printlock      = spi_prettyprint_status_register_amic_a25lq032,
+               .unlock         = NULL, /* Two status reg bytes (read with 0x35 and 0x05) */
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A29002B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A29002B,
+               .total_size     = 256,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A29002T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A29002T,
+               .total_size     = 256,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A29040B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A29040B,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "A49LF040A",
+               .bustype        = BUS_LPC,
+               .manufacture_id = AMIC_ID_NOPREFIX,
+               .model_id       = AMIC_A49LF040A,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF021",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF021,
+               .total_size     = 256,
+               .page_size      = 256,
+               /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df,
+               .unlock         = spi_disable_blockprotect_at25df,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF041A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF041A,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df,
+               .unlock         = spi_disable_blockprotect_at25df,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF081",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF081,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df,
+               .unlock         = spi_disable_blockprotect_at25df,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {1600, 2000}, /* Datasheet says range is 1.65-1.95 V */
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF081A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF081A,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df_sec,
+               .unlock         = spi_disable_blockprotect_at25df_sec,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF161",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF161,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PROBE,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df_sec,
+               .unlock         = spi_disable_blockprotect_at25df_sec,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF321",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF321,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df,
+               .unlock         = spi_disable_blockprotect_at25df,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF321A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF321A,
+               .total_size     = 4096,
+               .page_size      = 256,
+               /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df_sec,
+               .unlock         = spi_disable_blockprotect_at25df_sec,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DF641(A)",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DF641,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df_sec,
+               .unlock         = spi_disable_blockprotect_at25df_sec,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25DQ161",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25DQ161,
+               .total_size     = 2048,
+               .page_size      = 256,
+               /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df_sec,
+               .unlock         = spi_disable_blockprotect_at25df_sec,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25F512B",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25F512B,
+               .total_size     = 64,
+               .page_size      = 256,
+               /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25f,
+               .unlock         = spi_disable_blockprotect_at25f,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25FS010",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25FS010,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 32} },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { {4 * 1024, 32} },
+                               .block_erase = spi_block_erase_d7,
+                       }, {
+                               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25fs010,
+               .unlock         = spi_disable_blockprotect_at25fs010,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT25FS040",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT25FS040,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25fs040,
+               .unlock         = spi_disable_blockprotect_at25fs040,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT26DF041",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT26DF041,
+               .total_size     = 512,
+               .page_size      = 256,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 128} },
+                               .block_erase = spi_block_erase_20,
+                       }
+               },
+               .write          = NULL /* Incompatible Page write */,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600}, /* 3.0-3.6V for higher speed, 2.7-3.6V normal */
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT26DF081A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT26DF081A,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_atmel_at26df081a,
+               .unlock         = spi_disable_blockprotect_at25df,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT26DF161",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT26DF161,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PR,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_at25df,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT26DF161A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT26DF161A,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .printlock      = spi_prettyprint_status_register_atmel_at26df081a,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       /*The AT26DF321 has the same ID as the AT25DF321. */
+       /*{
+               .vendor         = "Atmel",
+               .name           = "AT26DF321",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT26DF321,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .printlock      = spi_prettyprint_status_register_atmel_at26df081a,
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+         },*/
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT26F004",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT26F004,
+               .total_size     = 512,
+               .page_size      = 256,
+               .tested         = TEST_UNTESTED,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT29C512",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT29C512,
+               .total_size     = 64,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10000, /* 10mS, Enter=Exec */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT29C010A",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT29C010A,
+               .total_size     = 128,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_jedec,
+               .probe_timing   = 10000, /* 10mS, Enter=Exec */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,  /* FIXME */
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT29C020",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT29C020,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = 10000,                        /* 10ms */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT29C040A",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT29C040A,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = 10000,                        /* 10 ms */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45CS1282",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45CS1282,
+               .total_size     = 16896 /* No power of two sizes */,
+               .page_size      = 1056 /* No power of two sizes */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL /* Incompatible Page write */,
+               .read           = NULL /* Incompatible read */,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB011D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB011D,
+               .total_size     = 128 /* Size can only be determined from status register */,
+               .page_size      = 256 /* Size can only be determined from status register */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB021D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB021D,
+               .total_size     = 256 /* Size can only be determined from status register */,
+               .page_size      = 256 /* Size can only be determined from status register */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB041D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB041D,
+               .total_size     = 512 /* Size can only be determined from status register */,
+               .page_size      = 256 /* Size can only be determined from status register */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+               .voltage        = {2500, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB081D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB081D,
+               .total_size     = 1024 /* Size can only be determined from status register */,
+               .page_size      = 256 /* Size can only be determined from status register */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+               .voltage        = {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB161D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB161D,
+               .total_size     = 2048 /* Size can only be determined from status register */,
+               .page_size      = 512 /* Size can only be determined from status register */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+               .voltage        = {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB321C",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB321C,
+               .total_size     = 4224 /* No power of two sizes */,
+               .page_size      = 528 /* No power of two sizes */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL /* Incompatible read */,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB321D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB321D,
+               .total_size     = 4096 /* Size can only be determined from status register */,
+               .page_size      = 512 /* Size can only be determined from status register */,
+               /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .feature_bits   = FEATURE_OTP,
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT45DB642D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT45DB642D,
+               .total_size     = 8192 /* Size can only be determined from status register */,
+               .page_size      = 1024 /* Size can only be determined from status register */,
+               /* does not support EWSR nor WREN and has no writable status register bits whatsoever */
+               .tested         = TEST_BAD_READ,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT49BV512",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT49BV512,
+               .total_size     = 64,
+               .page_size      = 64,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT49F002(N)",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT49F002N,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT49F002(N)T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT49F002NT,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT49F020",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT49F020,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,  /* Datasheet has no timing info specified */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+                       /* Chip features an optional permanent write protection
+                        * of the first 8 kB. The erase function is the same as
+                        * above, but 00000H to 01FFFH will not be erased.
+                        * FIXME: add another eraser when partial erasers are
+                        * supported.
+                        */
+               },
+               .printlock      = printlock_at49f,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT49F040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT49F040,
+               .total_size     = 512,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,  /* Datasheet has no timing info specified */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+                       /* Chip features an optional permanent write protection
+                        * of the first 16 kB. The erase function is the same as
+                        * above, but 00000H to 03FFFH will not be erased.
+                        * FIXME: add another eraser when partial erasers are
+                        * supported.
+                        */
+               },
+               .printlock      = printlock_at49f,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "AT49LH002",
+               .bustype        = BUS_LPC | BUS_FWH, /* A/A Mux */
+               .manufacture_id = ATMEL_ID,
+               .model_id       = ATMEL_AT49LH002,
+               .total_size     = 256,
+               .page_size      = 0, /* unused */
+               .feature_bits   = FEATURE_REGISTERMAP, /* TODO: LPC OK too? */
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_82802ab, /* TODO: 0xff cmd not documented? */
+               .probe_timing   = TIMING_FIXME,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {64 * 1024, 3},
+                                       {32 * 1024, 1},
+                                       {8 * 1024, 2},
+                                       {16 * 1024, 1},
+                               },
+                               .block_erase = erase_block_82802ab,
+                       }, {
+                               .eraseblocks = {
+                                       {64 * 1024, 4},
+                               },
+                               .block_erase = NULL, /* TODO: Implement. */
+                       },
+               },
+               .printlock      = NULL, /* TODO */
+               .unlock         = NULL, /* unlock_82802ab() not correct(?) */
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Catalyst",
+               .name           = "CAT28F512",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = CATALYST_ID,
+               .model_id       = CATALYST_CAT28F512,
+               .total_size     = 64,
+               .page_size      = 0, /* unused */
+               .feature_bits   = 0,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec, /* FIXME! */
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = NULL, /* TODO */
+                       },
+               },
+               .write          = NULL, /* TODO */
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Bright",
+               .name           = "BM29F040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = BRIGHT_ID,
+               .model_id       = BRIGHT_BM29F040,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "EMST",
+               .name           = "F49B002UA",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = EMST_ID,
+               .model_id       = EMST_F49B002UA,
+               .total_size     = 256,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "EMST",
+               .name           = "F25L008A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EMST_ID,
+               .model_id       = EMST_F25L008A,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EITHER,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_1,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B05",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B05,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B05T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B05,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B10",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B10,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B10T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B10,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B20",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B20,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B20T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B20,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B40",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B40,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B40T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B40,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B80",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B80T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B16T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B32T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B64",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25B64T",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25B64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25F05",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25F05,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25F10",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25F10,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25F20",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25F20,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25F40",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25F40,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PROBE,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25F80",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25F80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25F16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25F16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25F32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25F32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25Q40",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25Q40,
+               .total_size     = 512,
+               .page_size      = 256,
+               /* OTP: 256B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25Q80(A)",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25Q80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               /* OTP: 256B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               /* Note: EN25D16 is an evil twin which shares the model ID
+                  but has different write protection capabilities */
+               .vendor         = "Eon",
+               .name           = "EN25Q16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25Q16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               /* OTP: D16 512B/Q16 128B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 512} },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 32} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               /* not supported by Q16 version */
+                               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25Q32(A/B)",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25Q32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               /* OTP: 512B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .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 = { {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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25Q64",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25Q64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               /* OTP: 512B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 2048} },
+                               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25Q128",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25Q128,
+               .total_size     = 16384,
+               .page_size      = 256,
+               /* OTP: 512B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25QH16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25QH16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               /* supports SFDP */
+               /* OTP: 512B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 512} },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 32} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {1024 * 2048, 1} },
+                               .block_erase = spi_block_erase_60,
+                       }, {
+                               .eraseblocks = { {1024 * 2048, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN25QH32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .model_id       = EON_EN25QH32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               /* supports SFDP */
+               /* OTP: 512B total; enter 0x3A */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 1024} },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 64} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {1024 * 4096, 1} },
+                               .block_erase = spi_block_erase_60,
+                       }, {
+                               .eraseblocks = { {1024 * 4096, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN29F010",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = EON_ID,
+               .model_id       = EON_EN29F010,
+               .total_size     = 128,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PRE,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN29F002(A)(N)B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = EON_ID,
+               .model_id       = EON_EN29F002B,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN29F002(A)(N)T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = EON_ID,
+               .model_id       = EON_EN29F002T,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Eon",
+               .name           = "EN29LV640B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = EON_ID,
+               .model_id       = EON_EN29LV640B,
+               .total_size     = 8192,
+               .page_size      = 8192,
+               .feature_bits   = 0,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_en29lv640b,
+               .probe_timing   = TIMING_ZERO,  /* Datasheet has no timing info specified */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {8 * 1024, 8},
+                                       {64 * 1024, 127},
+                               },
+                               .block_erase = block_erase_en29lv640b,
+                       }, {
+                               .eraseblocks = { {8 * 1024 * 1024, 1} },
+                               .block_erase = block_erase_chip_en29lv640b,
+                       },
+               },
+               .write          = write_en29lv640b,
+               .read           = read_memmapped,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Fujitsu",
+               .name           = "MBM29F004BC",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = FUJITSU_ID,
+               .model_id       = FUJITSU_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_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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Fujitsu",
+               .name           = "MBM29F004TC",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = FUJITSU_ID,
+               .model_id       = FUJITSU_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_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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               /* FIXME: this has WORD/BYTE sequences; 2AA for word, 555 for byte */
+               .vendor         = "Fujitsu",
+               .name           = "MBM29F400BC",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = FUJITSU_ID,
+               .model_id       = FUJITSU_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 doesn't use probe_timing (m29f400bt.c) */
+               .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_m29f400bt,
+               .read           = read_memmapped,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "Fujitsu",
+               .name           = "MBM29F400TC",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = FUJITSU_ID,
+               .model_id       = FUJITSU_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 doesn't use probe_timing (m29f400bt.c) */
+               .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_m29f400bt,
+               .read           = read_memmapped,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "GigaDevice",
+               .name           = "GD25Q20",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GIGADEVICE_ID,
+               .model_id       = GIGADEVICE_GD25Q20,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "GigaDevice",
+               .name           = "GD25Q40",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GIGADEVICE_ID,
+               .model_id       = GIGADEVICE_GD25Q40,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "GigaDevice",
+               .name           = "GD25Q80",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GIGADEVICE_ID,
+               .model_id       = GIGADEVICE_GD25Q80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "GigaDevice",
+               .name           = "GD25Q16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GIGADEVICE_ID,
+               .model_id       = GIGADEVICE_GD25Q16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "GigaDevice",
+               .name           = "GD25Q32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GIGADEVICE_ID,
+               .model_id       = GIGADEVICE_GD25Q32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "GigaDevice",
+               .name           = "GD25Q64",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GIGADEVICE_ID,
+               .model_id       = GIGADEVICE_GD25Q64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "GigaDevice",
+               .name           = "GD25Q128",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GIGADEVICE_ID,
+               .model_id       = GIGADEVICE_GD25Q128,
+               .total_size     = 16384,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 4096} },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { {32 * 1024, 512} },
+                               .block_erase = spi_block_erase_52,
+                       }, {
+                               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "Hyundai",
+               .name           = "HY29F002T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = HYUNDAI_ID,
+               .model_id       = HYUNDAI_HY29F002T,
+               .total_size     = 256,
+               .page_size      = 256 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -45, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "Hyundai",
+               .name           = "HY29F002B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = HYUNDAI_ID,
+               .model_id       = HYUNDAI_HY29F002B,
+               .total_size     = 256,
+               .page_size      = 256 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -45, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "Hyundai",
+               .name           = "HY29F040A",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = HYUNDAI_ID,
+               .model_id       = HYUNDAI_HY29F040A,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Intel",
+               .name           = "28F001BN/BX-B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F001B,
+               .total_size     = 128,
+               .page_size      = 128 * 1024, /* 8k + 2x4k + 112k */
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Intel",
+               .name           = "28F001BN/BX-T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F001T,
+               .total_size     = 128,
+               .page_size      = 128 * 1024, /* 112k + 2x4k + 8k */
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Intel",
+               .name           = "28F002BC/BL/BV/BX-T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F002T,
+               .total_size     = 256,
+               .page_size      = 256 * 1024,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_82802ab,
+               .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_block_82802ab,
+                       },
+               },
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+       },
+
+       {
+               .vendor         = "Intel",
+               .name           = "28F008S3/S5/SC",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F004S3,
+               .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           = "28F004B5/BE/BV/BX-B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F004B,
+               .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           = "28F004B5/BE/BV/BX-T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F004T,
+               .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/BX/CE/CV-B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F400B,
+               .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/BX/CE/CV-T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_28F400T,
+               .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,
+       },
+
+       {
+               .vendor         = "Intel",
+               .name           = "82802AB",
+               .bustype        = BUS_FWH,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_82802AB,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = erase_block_82802ab,
+                       },
+               },
+               .unlock         = unlock_82802ab,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Intel",
+               .name           = "82802AC",
+               .bustype        = BUS_FWH,
+               .manufacture_id = INTEL_ID,
+               .model_id       = INTEL_82802AC,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 16} },
+                               .block_erase = erase_block_82802ab,
+                       },
+               },
+               .unlock         = unlock_82802ab,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L512",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L512,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L1005",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L1005,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L2005",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L2005,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L4005",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L4005,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L8005",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L8005,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L1605",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L1605,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L1635D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L1635D,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L1635E",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L1635E,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L3205",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L3205,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L3235D",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L3235D,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L6405",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L6405,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX25L12805",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX25L12805,
+               .total_size     = 16384,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX29F001B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX29F001B,
+               .total_size     = 128,
+               .page_size      = 32 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX29F001T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX29F001T,
+               .total_size     = 128,
+               .page_size      = 32 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX29F002(N)B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX29F002B,
+               .total_size     = 256,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX29F002(N)T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX29F002T,
+               .total_size     = 256,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX29F040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX29F040,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Macronix",
+               .name           = "MX29LV040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = MACRONIX_ID,
+               .model_id       = MACRONIX_MX29LV040,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "MoselVitelic",
+               .name           = "V29C51000B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = MVC_V29C51000B,
+               .total_size     = 64,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {512, 128} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "MoselVitelic",
+               .name           = "V29C51000T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = MVC_V29C51000T,
+               .total_size     = 64,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {512, 128} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "MoselVitelic",
+               .name           = "V29C51400B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = MVC_V29C51400B,
+               .total_size     = 512,
+               .page_size      = 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {1024, 512} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "MoselVitelic",
+               .name           = "V29C51400T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = MVC_V29C51400T,
+               .total_size     = 512,
+               .page_size      = 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {1024, 512} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "MoselVitelic",
+               .name           = "V29LC51000",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = MVC_V29LC51000,
+               .total_size     = 64,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {512, 128} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "MoselVitelic",
+               .name           = "V29LC51001",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = MVC_V29LC51001,
+               .total_size     = 128,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "MoselVitelic",
+               .name           = "V29LC51002",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = MVC_V29LC51002,
+               .total_size     = 256,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Numonyx",
+               .name           = "M25PE10",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PE10,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Numonyx",
+               .name           = "M25PE20",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PE20,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Numonyx",
+               .name           = "M25PE40",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PE40,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Numonyx",
+               .name           = "M25PE80",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PE80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Numonyx",
+               .name           = "M25PE16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PE16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Numonyx",
+               .name           = "N25Q064",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_N25Q064,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 2048 } },
+                               .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_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm25LV010",
+               .bustype        = BUS_SPI,
+               .manufacture_id = PMC_ID,
+               .model_id       = PMC_PM25LV010,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm25LV016B",
+               .bustype        = BUS_SPI,
+               .manufacture_id = PMC_ID,
+               .model_id       = PMC_PM25LV016B,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm25LV020",
+               .bustype        = BUS_SPI,
+               .manufacture_id = PMC_ID,
+               .model_id       = PMC_PM25LV020,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm25LV040",
+               .bustype        = BUS_SPI,
+               .manufacture_id = PMC_ID,
+               .model_id       = PMC_PM25LV040,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm25LV080B",
+               .bustype        = BUS_SPI,
+               .manufacture_id = PMC_ID,
+               .model_id       = PMC_PM25LV080B,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm25LV512",
+               .bustype        = BUS_SPI,
+               .manufacture_id = PMC_ID,
+               .model_id       = PMC_PM25LV512,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm29F002T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM29F002T,
+               .total_size     = 256,
+               .page_size      = 8 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_FIXME,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm29F002B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM29F002B,
+               .total_size     = 256,
+               .page_size      = 8 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_FIXME, 
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm39LV010",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM39F010, /* Pm39LV010 and Pm39F010 have identical IDs but different voltage */
+               .total_size     = 128,
+               .page_size      = 4096,
+               .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 = { {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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm39LV020",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM39LV020,
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm39LV040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM39LV040,
+               .total_size     = 512,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PR,
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm39LV512",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM39LV512,
+               .total_size     = 64,
+               .page_size      = 4096,
+               .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 = { {4 * 1024, 16} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = erase_block_jedec,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm49FL002",
+               .bustype        = BUS_LPC | BUS_FWH, /* A/A Mux */
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM49FL002,
+               .total_size     = 256,
+               .page_size      = 16 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "PMC",
+               .name           = "Pm49FL004",
+               .bustype        = BUS_LPC | BUS_FWH, /* A/A Mux */
+               .manufacture_id = PMC_ID_NOPREFIX,
+               .model_id       = PMC_PM49FL004,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Sanyo",
+               .name           = "LF25FW203A",
+               .bustype        = BUS_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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "Sharp",
+               .name           = "LH28F008BJT-BTLZ1",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SHARP_ID,
+               .model_id       = SHARP_LH28F008BJxxPB,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {8 * 1024, 8},
+                                       {64 * 1024, 15}
+                                },
+                               .block_erase = erase_block_82802ab,
+                       }, {
+                               .eraseblocks = { {1024 * 1024, 1} },
+                               .block_erase = erase_sector_49lfxxxc,
+                       }
+               },
+               .unlock         = unlock_lh28f008bjt,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Sharp",
+               .name           = "LHF00L04",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = SHARP_ID,
+               .model_id       = SHARP_LHF00L04,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET | FEATURE_REGISTERMAP,
+               .tested         = TEST_UNTESTED,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Spansion",
+               .name           = "S25FL004A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SPANSION_ID,
+               .model_id       = SPANSION_S25FL004A,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Spansion",
+               .name           = "S25FL008A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SPANSION_ID,
+               .model_id       = SPANSION_S25FL008A,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PRE,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Spansion",
+               .name           = "S25FL016A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SPANSION_ID,
+               .model_id       = SPANSION_S25FL016A,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PR,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Spansion",
+               .name           = "S25FL032A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SPANSION_ID,
+               .model_id       = SPANSION_S25FL032A,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 64} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {4 * 1024 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Spansion",
+               .name           = "S25FL064A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SPANSION_ID,
+               .model_id       = SPANSION_S25FL064A,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 128} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {8 * 1024 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25LF040A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF040_REMS,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_res2,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
+               .read           = spi_chip_read,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25LF080A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF080_REMS,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_res2,
+               .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 = { {1024 * 1024, 1} },
+                               .block_erase = spi_block_erase_60,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
+               .read           = spi_chip_read,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF010",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF010_REMS,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rems,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 32} },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { {32 * 1024, 4} },
+                               .block_erase = spi_block_erase_52,
+                       }, {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = spi_block_erase_60,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_1,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF016B",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF016B,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_aai_write,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF032B",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF032B,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_aai_write,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF064C",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF064C,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF040",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF040_REMS,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_spi_rems,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF040B",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF040B,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_aai_write,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF040B.REMS",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF040B_REMS,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_spi_rems,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_aai_write,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST25VF080B",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST25VF080B,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_EWSR,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       },
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_aai_write,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST28SF040A",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST28SF040,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = 0,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (sst28sf040.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {128, 4096} },
+                               .block_erase = erase_sector_28sf040,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_28sf040,
+                       }
+               },
+               .unlock         = unprotect_28sf040,
+               .write          = write_28sf040,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST29EE010",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST29EE010,
+               .total_size     = 128,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec,
+               .probe_timing   = 10, 
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST29LE010",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST29LE010,
+               .total_size     = 128,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = 10, 
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST29EE020A",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST29EE020A,
+               .total_size     = 256,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST29LE020",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST29LE020,
+               .total_size     = 256,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_jedec,
+               .probe_timing   = 10, 
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39SF512",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39SF512,
+               .total_size     = 64,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39SF010A",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39SF010,
+               .total_size     = 128,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 1,                    /* 150 ns */
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39SF020A",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39SF020,
+               .total_size     = 256,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 1,                    /* 150 ns */
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39SF040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39SF040,
+               .total_size     = 512,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 1,                    /* 150 ns */
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39VF512",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39VF512,
+               .total_size     = 64,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PRE,
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39VF010",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39VF010,
+               .total_size     = 128,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 1,                    /* 150 ns */
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39VF020",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39VF020,
+               .total_size     = 256,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = 1,                    /* 150 ns */
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39VF040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39VF040,
+               .total_size     = 512,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = 1,                    /* 150 ns */
+               .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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST39VF080",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST39VF080,
+               .total_size     = 1024,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .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 = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF002A/B",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF002A,
+               .total_size     = 256,
+               .page_size      = 16 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF003A/B",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF003A,
+               .total_size     = 384,
+               .page_size      = 64 * 1024,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               /* 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        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF004A,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF004C",
+               .bustype        = BUS_FWH,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF004C,
+               .total_size     = 512,
+               .page_size      = 4 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
+               .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_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF008A",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF008A,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF008C",
+               .bustype        = BUS_FWH,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF008C,
+               .total_size     = 1024,
+               .page_size      = 4 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
+               .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_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF016C",
+               .bustype        = BUS_FWH,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF016C,
+               .total_size     = 2048,
+               .page_size      = 4 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
+               .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_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF020",
+               .bustype        = BUS_LPC,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF020,
+               .total_size     = 256,
+               .page_size      = 16 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF020A",
+               .bustype        = BUS_LPC,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF020A,
+               .total_size     = 256,
+               .page_size      = 4 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PRE,
+               .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,
+                       }
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF040",
+               .bustype        = BUS_LPC,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF040,
+               .total_size     = 512,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PRE,
+               .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,
+                       }
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF040B",
+               .bustype        = BUS_LPC, /* A/A Mux */
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF040B,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET | FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .unlock         = unlock_82802ab,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF080A",
+               .bustype        = BUS_LPC, /* A/A Mux */
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF080A,
+               .total_size     = 1024,
+               .page_size      = 4096,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_FIXME, 
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SST",
+               .name           = "SST49LF160C",
+               .bustype        = BUS_LPC,
+               .manufacture_id = SST_ID,
+               .model_id       = SST_SST49LF160C,
+               .total_size     = 2048,
+               .page_size      = 4 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
+               .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_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P05-A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P05A,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {32 * 1024, 2} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       /* The ST M25P05 is a bit of a problem. It has the same ID as the
+        * ST M25P05-A in RES mode, but supports only 128 byte writes instead
+        * of 256 byte writes. We rely heavily on the fact that probe_spi_res1
+        * only is successful if RDID does not work.
+        */
+       {
+               .vendor         = "ST",
+               .name           = "M25P05",
+               .bustype        = BUS_SPI,
+               .manufacture_id = 0, /* Not used. */
+               .model_id       = ST_M25P05_RES,
+               .total_size     = 64,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_res1,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {32 * 1024, 2} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_1, /* 128 */
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P10-A",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P10A,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {32 * 1024, 4} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       /* The ST M25P10 has the same problem as the M25P05. */
+       {
+               .vendor         = "ST",
+               .name           = "M25P10",
+               .bustype        = BUS_SPI,
+               .manufacture_id = 0, /* Not used. */
+               .model_id       = ST_M25P10_RES,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_res1,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {32 * 1024, 4} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_1, /* 128 */
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P20",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P20,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 4} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST", /* Numonyx */
+               .name           = "M25P40",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P40,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P40-old",
+               .bustype        = BUS_SPI,
+               .manufacture_id = 0, /* Not used. */
+               .model_id       = ST_M25P40_RES,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_res1,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P80",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PR,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 64} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {4 * 1024 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P64",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 128} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {8 * 1024 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25P128",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25P128,
+               .total_size     = 16384,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {256 * 1024, 64} },
+                               .block_erase = spi_block_erase_d8,
+                       }, {
+                               .eraseblocks = { {16 * 1024 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25PX16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PX16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               /* OTP: 64B total; read 0x4B; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25PX32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PX32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M25PX64",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M25PX64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { { 4 * 1024, 2048 } },
+                               .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_c7,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M29F002B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ST_ID,
+               .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_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,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -X, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M29F002T/NT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M29F002T,
+               .total_size     = 256,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4750, 5250}, /* 4.75-5.25V for type -X, others 4.5-5.5V */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M29F040B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M29F040B,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO, /* datasheet specifies no timing */
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               /* FIXME: this has WORD/BYTE sequences; 2AA for word, 555 for byte */
+               .vendor         = "ST",
+               .name           = "M29F400BB",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M29F400BB,
+               .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 doesn't use probe_timing (m29f400bt.c) */
+               .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_m29f400bt,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+       {
+               /* FIXME: this has WORD/BYTE sequences; 2AA for word, 555 for byte */
+               .vendor         = "ST",
+               .name           = "M29F400BT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ST_ID,
+               .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 doesn't use probe_timing (m29f400bt.c) */
+               .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_m29f400bt,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M29W010B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ST_ID,
+               .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_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,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M29W040B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = ST_ID,
+               .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_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,
+               .voltage        = {2700, 3600},
+       },
+
+        {
+                .vendor         = "ST",
+                .name           = "M29W512B",
+               .bustype        = BUS_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_PRE,
+                .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,
+               .voltage        = {2700, 3600},
+        },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FLW040A",
+               .bustype        = BUS_FWH | BUS_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_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,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FLW040B",
+               .bustype        = BUS_FWH | BUS_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_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,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FLW080A",
+               .bustype        = BUS_FWH | BUS_LPC, /* A/A Mux */
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M50FLW080A,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PRE,
+               .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,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FLW080B",
+               .bustype        = BUS_FWH | BUS_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_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,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FW002",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M50FW002,
+               .total_size     = 256,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = {
+                                       {64 * 1024, 3},
+                                       {32 * 1024, 1},
+                                       {8 * 1024, 2},
+                                       {16 * 1024, 1},
+                               },
+                               .block_erase = erase_block_82802ab,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FW016",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = ST_ID,
+               .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 doesn't use probe_timing (82802ab.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 32}, },
+                               .block_erase = erase_block_82802ab,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FW040",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M50FW040,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8}, },
+                               .block_erase = erase_block_82802ab,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50FW080",
+               .bustype        = BUS_FWH, /* A/A Mux */
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M50FW080,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_82802ab,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 16}, },
+                               .block_erase = erase_block_82802ab,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "ST",
+               .name           = "M50LPW116",
+               .bustype        = BUS_LPC, /* A/A Mux */
+               .manufacture_id = ST_ID,
+               .model_id       = ST_M50LPW116,
+               .total_size     = 2048,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP,
+               .tested         = TEST_UNTESTED,
+               .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,
+                       }
+               },
+               .unlock         = unlock_stm50flw0x0x,
+               .write          = write_82802ab,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program & erase */
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{F,S,V}29C51001B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C51001B,
+               .total_size     = 128,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{F,S,V}29C51001T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C51001T,
+               .total_size     = 128,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{F,S,V}29C51002B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C51002B,
+               .total_size     = 256,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .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,
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{F,S,V}29C51002T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C51002T,
+               .total_size     = 256,
+               .page_size      = 512,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .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,
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{F,S,V}29C51004B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C51004B,
+               .total_size     = 512,
+               .page_size      = 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {1024, 512} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{F,S,V}29C51004T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C51004T,
+               .total_size     = 512,
+               .page_size      = 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {1024, 512} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{S,V}29C31004B",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C31004B,
+               .total_size     = 512,
+               .page_size      = 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,  /* Datasheet has no timing info specified */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {1024, 512} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "SyncMOS/MoselVitelic",
+               .name           = "{S,V}29C31004T",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = SYNCMOS_MVC_ID,
+               .model_id       = SM_MVC_29C31004T,
+               .total_size     = 512,
+               .page_size      = 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = TIMING_ZERO,  /* Datasheet has no timing info specified */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {1024, 512} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "TI",
+               .name           = "TMS29F002RB",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = TI_OLD_ID,
+               .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_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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "TI",
+               .name           = "TMS29F002RT",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = TI_OLD_ID,
+               .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_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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25Q80",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25Q80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25Q16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25Q16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25Q32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25Q32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25Q64",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25Q64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25Q128",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25Q128,
+               .total_size     = 16384,
+               .page_size      = 256,
+               /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */
+               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
+               .tested         = TEST_OK_PROBE,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 4096} },
+                               .block_erase = spi_block_erase_20,
+                       }, {
+                               .eraseblocks = { {32 * 1024, 512} },
+                               .block_erase = spi_block_erase_52,
+                       }, {
+                               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25X10",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25X10,
+               .total_size     = 128,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25X20",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25X20,
+               .total_size     = 256,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25X40",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25X40,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25X80",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25X80,
+               .total_size     = 1024,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_rdid,
+               .probe_timing   = TIMING_ZERO,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25X16",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25X16,
+               .total_size     = 2048,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PREW,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25X32",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25X32,
+               .total_size     = 4096,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W25X64",
+               .bustype        = BUS_SPI,
+               .manufacture_id = WINBOND_NEX_ID,
+               .model_id       = WINBOND_NEX_W25X64,
+               .total_size     = 8192,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_WRSR_WREN,
+               .tested         = TEST_OK_PROBE,
+               .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,
+                       }
+               },
+               .unlock         = spi_disable_blockprotect,
+               .write          = spi_chip_write_256,
+               .read           = spi_chip_read,
+               .voltage        = {2700, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W29C010(M)/W29C011A/W29EE011/W29EE012-old",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W29C010,
+               .total_size     = 128,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PRE,
+               .probe          = probe_w29ee011,
+               .probe_timing   = TIMING_IGNORED, /* routine doesn't use probe_timing (w29ee011.c) */
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+       },
+
+       {/* W29EE011, W29EE012, W29C010M, W29C011A do not support probe_jedec according to the datasheet, but it works for newer(?) steppings. */
+               .vendor         = "Winbond",
+               .name           = "W29C010(M)/W29C011A/W29EE011/W29EE012",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W29C010,
+               .total_size     = 128,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_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,
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W29C020(C)/W29C022",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W29C020,
+               .total_size     = 256,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W29C040/P",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W29C040,
+               .total_size     = 512,
+               .page_size      = 256,
+               .feature_bits   = FEATURE_LONG_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = 10, 
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39L040",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39L040,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .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,
+                       }
+               },
+               .printlock      = printlock_w39l040,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V040A",
+               .bustype        = BUS_LPC,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V040A,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .printlock      = printlock_w39v040a,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V040B",
+               .bustype        = BUS_LPC,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V040B,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .printlock      = printlock_w39v040b,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V040C",
+               .bustype        = BUS_LPC,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V040C,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V040FA",
+               .bustype        = BUS_FWH,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V040FA,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .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,
+                       }
+               },
+               .printlock      = printlock_w39v040fa,
+               .unlock         = unlock_sst_fwhub,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V040FB",
+               .bustype        = BUS_FWH,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V040B,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10, 
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .printlock      = printlock_w39v040fb,
+               .unlock         = unlock_w39v040fb,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program */
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V040FC",
+               .bustype        = BUS_FWH,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V040C,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .printlock      = printlock_w39v040fc,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program */
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V080A",
+               .bustype        = BUS_LPC,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V080A,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 16} },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {1024 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .printlock      = printlock_w39v080a,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W49F002U/N",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W49F002U,
+               .total_size     = 256,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W49F020",
+               .bustype        = BUS_PARALLEL,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W49F020,
+               .total_size     = 256,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PROBE,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {256 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {4500, 5500},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W49V002A",
+               .bustype        = BUS_LPC,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W49V002A,
+               .total_size     = 256,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W49V002FA",
+               .bustype        = BUS_FWH,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W49V002FA,
+               .total_size     = 256,
+               .page_size      = 128,
+               .feature_bits   = FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PR,
+               .probe          = probe_jedec,
+               .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,
+               .voltage        = {3000, 3600},
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V080FA",
+               .bustype        = BUS_FWH,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V080FA,
+               .total_size     = 1024,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 16}, },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {1024 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .printlock      = printlock_w39v080fa,
+               .unlock         = unlock_w39v080fa,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program */
+       },
+
+       {
+               .vendor         = "Winbond",
+               .name           = "W39V080FA (dual mode)",
+               .bustype        = BUS_FWH,
+               .manufacture_id = WINBOND_ID,
+               .model_id       = WINBOND_W39V080FA_DM,
+               .total_size     = 512,
+               .page_size      = 64 * 1024,
+               .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
+               .tested         = TEST_UNTESTED,
+               .probe          = probe_jedec,
+               .probe_timing   = 10,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {64 * 1024, 8}, },
+                               .block_erase = erase_sector_jedec,
+                       }, {
+                               .eraseblocks = { {512 * 1024, 1} },
+                               .block_erase = erase_chip_block_jedec,
+                       }
+               },
+               .printlock      = printlock_w39v080fa_dual,
+               .write          = write_jedec_1,
+               .read           = read_memmapped,
+               .voltage        = {3000, 3600}, /* Also has 12V fast program */
+       },
+       
+       {
+               .vendor         = "Unknown",
+               .name           = "SFDP-capable chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = GENERIC_MANUF_ID,
+               .model_id       = SFDP_DEVICE_ID,
+               /* We present our own "report this" text hence we do not
+                * want the default "This flash part has status UNTESTED..."
+                * text to be printed. */
+               .tested         = TEST_OK_PREW,
+               .probe          = probe_spi_sfdp,
+               .unlock         = spi_disable_blockprotect, /* is this safe? */
+               .read           = spi_chip_read,
+               /* FIXME: some vendor extensions define this */
+               .voltage        = {},
+                /* Everything below will be set by the probing function. */
+               .write          = NULL,
+               .total_size     = 0,
+               .page_size      = 0,
+               .feature_bits   = 0,
+               .block_erasers  = {},
+       },
+
+       {
+               .vendor         = "Programmer",
+               .name           = "Opaque flash chip",
+               .bustype        = BUS_PROG,
+               .manufacture_id = PROGMANUF_ID,
+               .model_id       = PROGDEV_ID,
+               .total_size     = 0,
+               .page_size      = 256,
+               /* probe is assumed to work, rest will be filled in by probe */
+               .tested         = TEST_OK_PROBE,
+               .probe          = probe_opaque,
+               /* eraseblock sizes will be set by the probing function */
+               .block_erasers  =
+               {
+                       {
+                               .block_erase = erase_opaque,
+                       }
+               },
+               .write          = write_opaque,
+               .read           = read_opaque,
+       },
+
+       {
+               .vendor         = "AMIC",
+               .name           = "unknown AMIC SPI chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = AMIC_ID,
+               .model_id       = GENERIC_DEVICE_ID,
+               .total_size     = 0,
+               .page_size      = 256,
+               .tested         = TEST_BAD_PREW,
+               .probe          = probe_spi_rdid4,
+               .probe_timing   = TIMING_ZERO,
+               .write          = NULL,
+               .read           = NULL,
+       },
+
+       {
+               .vendor         = "Atmel",
+               .name           = "unknown Atmel SPI chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ATMEL_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         = "Eon",
+               .name           = "unknown Eon SPI chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = EON_ID_NOPREFIX,
+               .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         = "Macronix",
+               .name           = "unknown Macronix SPI chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = MACRONIX_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         = "PMC",
+               .name           = "unknown PMC SPI chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = PMC_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         = "SST",
+               .name           = "unknown SST SPI chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = SST_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         = "ST",
+               .name           = "unknown ST SPI chip",
+               .bustype        = BUS_SPI,
+               .manufacture_id = ST_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         = "Sanyo",
+               .name           = "unknown Sanyo SPI chip",
+               .bustype        = BUS_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        = BUS_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        = BUS_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
new file mode 100644 (file)
index 0000000..0ecb5f3
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
+ * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
+ * Copyright (C) 2006-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
+ */
+
+#ifndef __FLASHCHIPS_H__
+#define __FLASHCHIPS_H__ 1
+
+/*
+ * Please keep this list sorted alphabetically by manufacturer. The first
+ * entry of each section should be the manufacturer ID, followed by the
+ * list of devices from that manufacturer (sorted by device IDs).
+ *
+ * All LPC/FWH parts (parallel flash) have 8-bit device IDs if there is no
+ * continuation code.
+ * 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 SFDP_DEVICE_ID         0xFFFE
+#define PROGMANUF_ID           0xFFFE  /* dummy ID for opaque chips behind a programmer */
+#define PROGDEV_ID             0x01    /* dummy ID for opaque chips behind a programmer */
+
+#define ALLIANCE_ID            0x52    /* Alliance Semiconductor */
+#define ALLIANCE_AS29F002B     0x34
+#define ALLIANCE_AS29F002T     0xB0
+#define ALLIANCE_AS29F010      0x04
+#define ALLIANCE_AS29F040      0xA4
+#define ALLIANCE_AS29F200B     0x57
+#define ALLIANCE_AS29F200T     0x51
+#define ALLIANCE_AS29LV160B    0x49
+#define ALLIANCE_AS29LV160T    0xCA
+#define ALLIANCE_AS29LV400B    0xBA
+#define ALLIANCE_AS29LV400T    0xB9
+#define ALLIANCE_AS29LV800B    0x5B
+#define ALLIANCE_AS29LV800T    0xDA
+
+#define AMD_ID                 0x01    /* AMD */
+#define AMD_AM29DL400BT                0x0C
+#define AMD_AM29DL400BB                0x0F
+#define AMD_AM29DL800BT                0x4A
+#define AMD_AM29DL800BB                0xCB
+#define AMD_AM29F002BB         0x34    /* Same as Am29F002NBB */
+#define AMD_AM29F002BT         0xB0    /* Same as Am29F002NBT */
+#define AMD_AM29F004BB         0x7B
+#define AMD_AM29F004BT         0x77
+#define AMD_AM29F016D          0xAD
+#define AMD_AM29F010B          0x20    /* Same as Am29F010A */
+#define AMD_AM29F040B          0xA4
+#define AMD_AM29F080B          0xD5
+#define AMD_AM29F200BB         0x57
+#define AMD_AM29F200BT         0x51
+#define AMD_AM29F400BB         0xAB
+#define AMD_AM29F400BT         0x23
+#define AMD_AM29F800BB         0x58
+#define AMD_AM29F800BT         0xD6
+#define AMD_AM29LV001BB                0x6D
+#define AMD_AM29LV001BT                0xED
+#define AMD_AM29LV002BB                0xC2
+#define AMD_AM29LV002BT                0x40
+#define AMD_AM29LV004BB                0xB6
+#define AMD_AM29LV004BT                0xB5
+#define AMD_AM29LV008BB                0x37
+#define AMD_AM29LV008BT                0x3E
+#define AMD_AM29LV040B         0x4F
+#define AMD_AM29LV080B         0x38    /* Same as Am29LV081B */
+#define AMD_AM29LV200BB                0xBF
+#define AMD_AM29LV200BT                0x3B
+#define AMD_AM29LV800BB                0x5B    /* Same as Am29LV800DB */
+#define AMD_AM29LV400BT                0xB9
+#define AMD_AM29LV400BB                0xBA
+#define AMD_AM29LV800BT                0xDA    /* Same as Am29LV800DT */
+
+#define AMIC_ID                        0x7F37  /* AMIC */
+#define AMIC_ID_NOPREFIX       0x37    /* AMIC */
+#define AMIC_A25L05PT          0x2020
+#define AMIC_A25L05PU          0x2010
+#define AMIC_A25L10PT          0x2021
+#define AMIC_A25L10PU          0x2011
+#define AMIC_A25L20PT          0x2022
+#define AMIC_A25L20PU          0x2012
+#define AMIC_A25L40PT          0x2013  /* Datasheet says T and U have
+                                          same device ID. Confirmed by
+                                          hardware testing. */
+#define AMIC_A25L40PU          0x2013
+#define AMIC_A25L80P           0x2014  /* Seems that no A25L80PT exists */
+#define AMIC_A25L16PT          0x2025
+#define AMIC_A25L16PU          0x2015
+#define AMIC_A25L512           0x3010
+#define AMIC_A25L010           0x3011
+#define AMIC_A25L020           0x3012
+#define AMIC_A25L040           0x3013
+#define AMIC_A25L080           0x3014
+#define AMIC_A25L016           0x3015
+#define AMIC_A25L032           0x3016
+#define AMIC_A25LQ032          0x4016
+#define AMIC_A29002B           0x0d
+#define AMIC_A29002T           0x8C    /* Same as A290021T */
+#define AMIC_A29040B           0x86
+#define AMIC_A29400T           0xB0    /* Same as 294001T */
+#define AMIC_A29400U           0x31    /* Same as A294001U */
+#define AMIC_A29800T           0x0E
+#define AMIC_A29800U           0x8F
+#define AMIC_A29L004T          0x34    /* Same as A29L400T */
+#define AMIC_A29L004U          0xB5    /* Same as A29L400U */
+#define AMIC_A29L008T          0x1A    /* Same as A29L800T */
+#define AMIC_A29L008U          0x9B    /* Same as A29L800U */
+#define AMIC_A29L040           0x92
+#define AMIC_A49LF040A         0x9d
+
+#define ATMEL_ID               0x1F    /* Atmel */
+#define ATMEL_AT25DF021                0x4300
+#define ATMEL_AT25DF041A       0x4401
+#define ATMEL_AT25DF081                0x4502
+#define ATMEL_AT25DF081A       0x4501  /* Yes, 81A has a lower number than 81 */
+#define ATMEL_AT25DF161                0x4602
+#define ATMEL_AT25DF321                0x4700  /* Same as 26DF321 */
+#define ATMEL_AT25DF321A       0x4701
+#define ATMEL_AT25DF641                0x4800
+#define ATMEL_AT25DQ161                0x8600
+#define ATMEL_AT25F512         /* No device ID found in datasheet. Vendor ID
+                                * can be read with AT25F512A_RDID */
+#define ATMEL_AT25F512A                0x65 /* Needs AT25F512A_RDID */
+#define ATMEL_AT25F512B                0x6500
+#define ATMEL_AT25F1024                /* No device ID found in datasheet. Vendor ID
+                                * can be read with AT25F512A_RDID */
+#define ATMEL_AT25F1024A               0x60 /* Needs AT25F512A_RDID */
+#define ATMEL_AT25FS010                0x6601
+#define ATMEL_AT25FS040                0x6604
+#define ATMEL_AT26DF041                0x4400
+#define ATMEL_AT26DF081                0x4500  /* guessed, no datasheet available */
+#define ATMEL_AT26DF081A       0x4501
+#define ATMEL_AT26DF161                0x4600
+#define ATMEL_AT26DF161A       0x4601
+#define ATMEL_AT26DF321                0x4700  /* Same as 25DF321 */
+#define ATMEL_AT26F004         0x0400
+#define ATMEL_AT29C040A                0xA4
+#define ATMEL_AT29C010A                0xD5
+#define ATMEL_AT29C020         0xDA
+#define ATMEL_AT29C512         0x5D
+#define ATMEL_AT45BR3214B      /* No ID available */
+#define ATMEL_AT45CS1282       0x2920
+#define ATMEL_AT45D011         /* No ID available */
+#define ATMEL_AT45D021A                /* No ID available */
+#define ATMEL_AT45D041A                /* No ID available */
+#define ATMEL_AT45D081A                /* No ID available */
+#define ATMEL_AT45D161         /* No ID available */
+#define ATMEL_AT45DB011                /* No ID available */
+#define ATMEL_AT45DB011B       /* No ID available */
+#define ATMEL_AT45DB011D       0x2200
+#define ATMEL_AT45DB021A       /* No ID available */
+#define ATMEL_AT45DB021B       /* No ID available */
+#define ATMEL_AT45DB021D       0x2300
+#define ATMEL_AT45DB041A       /* No ID available */
+#define ATMEL_AT45DB041D       0x2400
+#define ATMEL_AT45DB081A       /* No ID available */
+#define ATMEL_AT45DB081D       0x2500
+#define ATMEL_AT45DB161                /* No ID available */
+#define ATMEL_AT45DB161B       /* No ID available */
+#define ATMEL_AT45DB161D       0x2600
+#define ATMEL_AT45DB321                /* No ID available */
+#define ATMEL_AT45DB321B       /* No ID available */
+#define ATMEL_AT45DB321C       0x2700
+#define ATMEL_AT45DB321D       0x2701 /* Buggy data sheet */
+#define ATMEL_AT45DB642                /* No ID available */
+#define ATMEL_AT45DB642D       0x2800
+#define ATMEL_AT49BV512                0x03
+#define ATMEL_AT49F002N                0x07    /* for AT49F002(N)  */
+#define ATMEL_AT49LH002                0xE9
+#define ATMEL_AT49F002NT       0x08    /* for AT49F002(N)T */
+#define ATMEL_AT49F020         0x0B
+#define ATMEL_AT49F040         0x13
+
+/* Bright Microelectronics has the same manufacturer ID as Hyundai... */
+#define BRIGHT_ID              0xAD    /* Bright Microelectronics */
+#define BRIGHT_BM29F040                0x40
+#define BRIGHT_BM29F400B       0xAB
+#define BRIGHT_BM29F400T       0xAD
+
+#define CATALYST_ID            0x31    /* Catalyst */
+#define CATALYST_CAT28F512     0xB8
+
+#define EMST_ID                        0x8C    /* EMST / EFST Elite Flash Storage */
+#define EMST_F25L008A          0x2014
+#define EMST_F49B002UA         0x00
+
+/*
+ * EN25 chips are SPI, first byte of device ID is memory type,
+ * second byte of device ID is log(bitsize)-9.
+ * Vendor and device ID of EN29 series are both prefixed with 0x7F, which
+ * is the continuation code for IDs in bank 2.
+ * Vendor ID of EN25 series is NOT prefixed with 0x7F, this results in
+ * a collision with Mitsubishi. Mitsubishi once manufactured flash chips.
+ * Let's hope they are not manufacturing SPI flash chips as well.
+ */
+#define EON_ID                 0x7F1C  /* EON Silicon Devices */
+#define EON_ID_NOPREFIX                0x1C    /* EON, missing 0x7F prefix */
+#define EON_EN25B05            0x2010  /* Same as P05, 2^19 kbit or 2^16 kByte */
+#define EON_EN25B05T           0x25
+#define EON_EN25B05B           0x95
+#define EON_EN25B10            0x2011  /* Same as P10 */
+#define EON_EN25B10T           0x40
+#define EON_EN25B10B           0x30
+#define EON_EN25B20            0x2012  /* Same as P20 */
+#define EON_EN25B20T           0x41
+#define EON_EN25B20B           0x31
+#define EON_EN25B40            0x2013  /* Same as P40 */
+#define EON_EN25B40T           0x42
+#define EON_EN25B40B           0x32
+#define EON_EN25B80            0x2014  /* Same as P80 */
+#define EON_EN25B80T           0x43
+#define EON_EN25B80B           0x33
+#define EON_EN25B16            0x2015  /* Same as P16 */
+#define EON_EN25B16T           0x44
+#define EON_EN25B16B           0x34
+#define EON_EN25B32            0x2016  /* Same as P32 */
+#define EON_EN25B32T           0x45
+#define EON_EN25B32B           0x35
+#define EON_EN25B64            0x2017  /* Same as P64 */
+#define EON_EN25B64T           0x46
+#define EON_EN25B64B           0x36
+#define EON_EN25F05            0x3110
+#define EON_EN25F10            0x3111
+#define EON_EN25F20            0x3112
+#define EON_EN25F40            0x3113
+#define EON_EN25F80            0x3114
+#define EON_EN25F16            0x3115
+#define EON_EN25F32            0x3116
+#define EON_EN25Q40            0x3013
+#define EON_EN25Q80            0x3014
+#define EON_EN25Q16            0x3015  /* Same as EN25D16 */
+#define EON_EN25Q32            0x3016  /* Same as EN25Q32A and EN25Q32B */
+#define EON_EN25Q64            0x3017
+#define EON_EN25Q128           0x3018
+#define EON_EN25QH16           0x7015
+#define EON_EN25QH32           0x7016
+#define EON_EN29F512           0x7F21
+#define EON_EN29F010           0x20
+#define EON_EN29F040A          0x7F04
+#define EON_EN29LV010          0x7F6E
+#define EON_EN29LV040A         0x7F4F  /* EN29LV040(A) */
+#define EON_EN29LV640B         0xCB
+#define EON_EN29F002T          0x7F92  /* Same as EN29F002A */
+#define EON_EN29F002B          0x7F97  /* Same as EN29F002AN */
+
+#define FUJITSU_ID             0x04    /* Fujitsu */
+#define FUJITSU_MBM29DL400BC   0x0F
+#define FUJITSU_MBM29DL400TC   0x0C
+#define FUJITSU_MBM29DL800BA   0xCB
+#define FUJITSU_MBM29DL800TA   0x4A
+#define FUJITSU_MBM29F002BC    0x34
+#define FUJITSU_MBM29F002TC    0xB0
+#define FUJITSU_MBM29F004BC    0x7B
+#define FUJITSU_MBM29F004TC    0x77
+#define FUJITSU_MBM29F040C     0xA4
+#define FUJITSU_MBM29F080A     0xD5
+#define FUJITSU_MBM29F200BC    0x57
+#define FUJITSU_MBM29F200TC    0x51
+#define FUJITSU_MBM29F400BC    0xAB
+#define FUJITSU_MBM29F400TC    0x23
+#define FUJITSU_MBM29F800BA    0x58
+#define FUJITSU_MBM29F800TA    0xD6
+#define FUJITSU_MBM29LV002BC   0xC2
+#define FUJITSU_MBM29LV002TC   0x40
+#define FUJITSU_MBM29LV004BC   0xB6
+#define FUJITSU_MBM29LV004TC   0xB5
+#define FUJITSU_MBM29LV008BA   0x37
+#define FUJITSU_MBM29LV008TA   0x3E
+#define FUJITSU_MBM29LV080A    0x38
+#define FUJITSU_MBM29LV200BC   0xBF
+#define FUJITSU_MBM29LV200TC   0x3B
+#define FUJITSU_MBM29LV400BC   0xBA
+#define FUJITSU_MBM29LV400TC   0xB9
+#define FUJITSU_MBM29LV800BA   0x5B    /* Same as MBM29LV800BE */
+#define FUJITSU_MBM29LV800TA   0xDA    /* Same as MBM29LV800TE */
+
+#define GIGADEVICE_ID          0xC8    /* GigaDevice */
+#define GIGADEVICE_GD25Q20     0x4012
+#define GIGADEVICE_GD25Q40     0x4013
+#define GIGADEVICE_GD25Q80     0x4014
+#define GIGADEVICE_GD25Q16     0x4015
+#define GIGADEVICE_GD25Q32     0x4016
+#define GIGADEVICE_GD25Q64     0x4017
+#define GIGADEVICE_GD25Q128    0x4018
+
+#define HYUNDAI_ID             0xAD    /* Hyundai */
+#define HYUNDAI_HY29F400T      0x23    /* Same as HY29F400AT */
+#define HYUNDAI_HY29F800B      0x58    /* Same as HY29F800AB */
+#define HYUNDAI_HY29LV800B     0x5B
+#define HYUNDAI_HY29F040A      0xA4
+#define HYUNDAI_HY29F400B      0xAB    /* Same as HY29F400AB */
+#define HYUNDAI_HY29F002B      0x34
+#define HYUNDAI_HY29F002T      0xB0
+#define HYUNDAI_HY29LV400T     0xB9
+#define HYUNDAI_HY29LV400B     0xBA
+#define HYUNDAI_HY29F080       0xD5
+#define HYUNDAI_HY29F800T      0xD6    /* Same as HY29F800AT */
+#define HYUNDAI_HY29LV800T     0xDA
+
+#define IMT_ID                 0x7F1F  /* Integrated Memory Technologies */
+#define IMT_IM29F004B          0xAE
+#define IMT_IM29F004T          0xAF
+
+#define INTEL_ID               0x89    /* Intel */
+#define INTEL_28F320J5         0x14
+#define INTEL_28F640J5         0x15
+#define INTEL_28F320J3         0x16
+#define INTEL_28F640J3         0x17
+#define INTEL_28F128J3         0x18
+#define INTEL_28F256J3         0x1D
+#define INTEL_28F400T          0x70    /* 28F400BV/BX/CE/CV-T */
+#define INTEL_28F400B          0x71    /* 28F400BV/BX/CE/CV-B */
+#define INTEL_28F200T          0x74    /* 28F200BL/BV/BX/CV-T */
+#define INTEL_28F200B          0x75    /* 28F200BL/BV/BX/CV-B */
+#define INTEL_28F004T          0x78    /* 28F004B5/BE/BV/BX-T */
+#define INTEL_28F004B          0x79    /* 28F004B5/BE/BV/BX-B */
+#define INTEL_28F002T          0x7C    /* 28F002BC/BL/BV/BX-T */
+#define INTEL_28F002B          0x7D    /* 28F002BL/BV/BX-B */
+#define INTEL_28F001T          0x94    /* 28F001BN/BX-T */
+#define INTEL_28F001B          0x95    /* 28F001BN/BX-B */
+#define INTEL_28F008T          0x98    /* 28F008BE/BV-T */
+#define INTEL_28F008B          0x99    /* 28F008BE/BV-B */
+#define INTEL_28F800T          0x9C    /* 28F800B5/BV/CE/CV-T */
+#define INTEL_28F800B          0x9D    /* 28F800B5/BV/CE/CV-B */
+#define INTEL_28F016SV         0xA0    /* 28F016SA/SV */
+#define INTEL_28F008SA         0xA2
+#define INTEL_28F008S3         0xA6    /* 28F008S3/S5/SC */
+#define INTEL_28F004S3         0xA7    /* 28F008S3/S5/SC */
+#define INTEL_28F016XS         0xA8
+#define INTEL_28F016S3         0xAA    /* 28F016S3/S5/SC */
+#define INTEL_82802AC          0xAC
+#define INTEL_82802AB          0xAD
+#define INTEL_28F010           0xB4
+#define INTEL_28F512           0xB8
+#define INTEL_28F256A          0xB9
+#define INTEL_28F020           0xBD
+#define INTEL_28F016B3T                0xD0    /* 28F016B3-T */
+#define INTEL_28F016B3B                0xD1    /* 28F016B3-B */
+#define INTEL_28F008B3T                0xD2    /* 28F008B3-T */
+#define INTEL_28F008B3B                0xD3    /* 28F008B3-B */
+#define INTEL_28F004B3T                0xD4    /* 28F004B3-T */
+#define INTEL_28F004B3B                0xD5    /* 28F004B3-B */
+
+#define SHARP_LH28F008SA       0xA2    /* Sharp chip, Intel Vendor ID */
+#define SHARP_LH28F008SC       0xA6    /* Sharp chip, Intel Vendor ID */
+
+#define ISSI_ID                        0xD5    /* ISSI Integrated Silicon Solutions */
+
+/*
+ * MX25 chips are SPI, first byte of device ID is memory type,
+ * second byte of device ID is log(bitsize)-9.
+ * Generalplus SPI chips seem to be compatible with Macronix
+ * and use the same set of IDs.
+ */
+#define MACRONIX_ID            0xC2    /* Macronix (MX) */
+#define MACRONIX_MX25L512      0x2010  /* Same as MX25V512 */
+#define MACRONIX_MX25L1005     0x2011
+#define MACRONIX_MX25L2005     0x2012
+#define MACRONIX_MX25L4005     0x2013  /* MX25L4005{,A} */
+#define MACRONIX_MX25L8005     0x2014  /* Same as MX25V8005 */
+#define MACRONIX_MX25L1605     0x2015  /* MX25L1605{,A,D} */
+#define MACRONIX_MX25L3205     0x2016  /* MX25L3205{,A} */
+#define MACRONIX_MX25L6405     0x2017  /* MX25L6405{,D}, MX25L6406E, MX25L6436E */
+#define MACRONIX_MX25L12805    0x2018  /* MX25L12805 */
+#define MACRONIX_MX25L1635D    0x2415
+#define MACRONIX_MX25L1635E    0x2515  /* MX25L1635{E} */
+#define MACRONIX_MX25L3235D    0x5E16  /* MX25L3225D/MX25L3235D/MX25L3237D */
+#define MACRONIX_MX29F001B     0x19
+#define MACRONIX_MX29F001T     0x18
+#define MACRONIX_MX29F002B     0x34    /* Same as MX29F002NB; N has reset pin n/c. */
+#define MACRONIX_MX29F002T     0xB0    /* Same as MX29F002NT; N has reset pin n/c. */
+#define MACRONIX_MX29F004B     0x46
+#define MACRONIX_MX29F004T     0x45
+#define MACRONIX_MX29F022T     0x36    /* Same as MX29F022NT */
+#define MACRONIX_MX29F040      0xA4    /* Same as MX29F040C */
+#define MACRONIX_MX29F080      0xD5
+#define MACRONIX_MX29F200B     0x57    /* Same as MX29F200CB */
+#define MACRONIX_MX29F200T     0x51    /* Same as MX29F200CT */
+#define MACRONIX_MX29F400B     0xAB    /* Same as MX29F400CB */
+#define MACRONIX_MX29F400T     0x23    /* Same as MX29F400CT */
+#define MACRONIX_MX29F800B     0x58
+#define MACRONIX_MX29F800T     0xD6
+#define MACRONIX_MX29LV002CB   0x5A
+#define MACRONIX_MX29LV002CT   0x59
+#define MACRONIX_MX29LV004B    0xB6    /* Same as MX29LV004CB */
+#define MACRONIX_MX29LV004T    0xB5    /* Same as MX29LV004CT */
+#define MACRONIX_MX29LV008B    0x37    /* Same as MX29LV008CB */
+#define MACRONIX_MX29LV008T    0x3E    /* Same as MX29LV008CT */
+#define MACRONIX_MX29LV040     0x4F    /* Same as MX29LV040C */
+#define MACRONIX_MX29LV081     0x38
+#define MACRONIX_MX29LV128DB   0x7A
+#define MACRONIX_MX29LV128DT   0x7E
+#define MACRONIX_MX29LV160DB   0x49    /* Same as MX29LV161DB/MX29LV160CB */
+#define MACRONIX_MX29LV160DT   0xC4    /* Same as MX29LV161DT/MX29LV160CT */
+#define MACRONIX_MX29LV320DB   0xA8    /* Same as MX29LV321DB */
+#define MACRONIX_MX29LV320DT   0xA7    /* Same as MX29LV321DT */
+#define MACRONIX_MX29LV400B    0xBA    /* Same as MX29LV400CB */
+#define MACRONIX_MX29LV400T    0xB9    /* Same as MX29LV400CT */
+#define MACRONIX_MX29LV640DB   0xCB    /* Same as MX29LV640EB */
+#define MACRONIX_MX29LV640DT   0xC9    /* Same as MX29LV640ET */
+#define MACRONIX_MX29LV800B    0x5B    /* Same as MX29LV800CB */
+#define MACRONIX_MX29LV800T    0xDA    /* Same as MX29LV800CT */
+#define MACRONIX_MX29SL402CB   0xF1
+#define MACRONIX_MX29SL402CT   0x70
+#define MACRONIX_MX29SL800CB   0x6B    /* Same as MX29SL802CB */
+#define MACRONIX_MX29SL800CT   0xEA    /* Same as MX29SL802CT */
+
+/*
+ * Programmable Micro Corp is listed in JEP106W in bank 2, so it should
+ * have a 0x7F continuation code prefix.
+ */
+#define PMC_ID                 0x7F9D  /* PMC */
+#define PMC_ID_NOPREFIX                0x9D    /* PMC, missing 0x7F prefix */
+#define PMC_PM25LV512          0x7B
+#define PMC_PM25LV010          0x7C
+#define PMC_PM25LV020          0x7D
+#define PMC_PM25LV040          0x7E
+#define PMC_PM25LV080B         0x13
+#define PMC_PM25LV016B         0x14
+#define PMC_PM29F002T          0x1D
+#define PMC_PM29F002B          0x2D
+#define PMC_PM39LV512          0x1B
+#define PMC_PM39F010           0x1C    /* Same as Pm39LV010 */
+#define PMC_PM39LV020          0x3D
+#define PMC_PM39LV040          0x3E
+#define PMC_PM39F020           0x4D
+#define PMC_PM39F040           0x4E
+#define PMC_PM49FL002          0x6D
+#define PMC_PM49FL004          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
+#define SHARP_LH28F800BVxxBTL  0x4B
+#define SHARP_LH28F800BVxxBV   0x4D
+#define SHARP_LH28F800BVxxTV   0x4C
+#define SHARP_LHF00L02         0xC9    /* Same as LHF00L06/LHF00L07 */
+#define SHARP_LHF00L04         0xCF    /* Same as LHF00L03/LHF00L05 */
+
+/*
+ * Spansion was previously a joint venture of AMD and Fujitsu.
+ * S25 chips are SPI. The first device ID byte is memory type and
+ * the second device ID byte is memory capacity.
+ */
+#define SPANSION_ID            0x01    /* Spansion, same ID as AMD */
+#define SPANSION_S25FL004A     0x0212
+#define SPANSION_S25FL008A     0x0213
+#define SPANSION_S25FL016A     0x0214
+#define SPANSION_S25FL032A     0x0215
+#define SPANSION_S25FL064A     0x0216
+
+/*
+ * SST25 chips are SPI, first byte of device ID is memory type, second
+ * byte of device ID is related to log(bitsize) at least for some chips.
+ */
+#define SST_ID                 0xBF    /* SST */
+#define SST_SST25WF512         0x2501
+#define SST_SST25WF010         0x2502
+#define SST_SST25WF020         0x2503
+#define SST_SST25WF040         0x2504
+#define SST_SST25VF512A_REMS   0x48    /* REMS or RES opcode */
+#define SST_SST25VF010_REMS    0x49    /* REMS or RES opcode */
+#define SST_SST25VF020_REMS    0x43    /* REMS or RES opcode */
+#define SST_SST25VF040_REMS    0x44    /* REMS or RES opcode, same as SST25LF040A */
+#define SST_SST25VF040B                0x258D
+#define SST_SST25VF040B_REMS   0x8D    /* REMS or RES opcode */
+#define SST_SST25VF080_REMS    0x80    /* REMS or RES opcode, same as SST25LF080A */
+#define SST_SST25VF080B                0x258E
+#define SST_SST25VF080B_REMS   0x8E    /* REMS or RES opcode */
+#define SST_SST25VF016B                0x2541
+#define SST_SST25VF032B                0x254A
+#define SST_SST25VF032B_REMS   0x4A    /* REMS or RES opcode */
+#define SST_SST25VF064C                0x254B
+#define SST_SST26VF016         0x2601
+#define SST_SST26VF032         0x2602
+#define SST_SST27SF512         0xA4
+#define SST_SST27SF010         0xA5
+#define SST_SST27SF020         0xA6
+#define SST_SST27VF010         0xA9
+#define SST_SST27VF020         0xAA
+#define SST_SST28SF040         0x04
+#define SST_SST29EE512         0x5D
+#define SST_SST29EE010         0x07
+#define SST_SST29LE010         0x08    /* Same as SST29VE010 */
+#define SST_SST29EE020A                0x10    /* Same as SST29EE020 */
+#define SST_SST29LE020         0x12    /* Same as SST29VE020 */
+#define SST_SST29SF020         0x24
+#define SST_SST29VF020         0x25
+#define SST_SST29SF040         0x13
+#define SST_SST29VF040         0x14
+#define SST_SST39SF512         0xB4
+#define SST_SST39SF010         0xB5
+#define SST_SST39SF020         0xB6    /* Same as 39SF020A */
+#define SST_SST39SF040         0xB7
+#define SST_SST39VF512         0xD4
+#define SST_SST39VF010         0xD5
+#define SST_SST39VF020         0xD6    /* Same as 39LF020 */
+#define SST_SST39VF040         0xD7    /* Same as 39LF040 */
+#define SST_SST39VF080         0xD8    /* Same as 39LF080/39VF080/39VF088 */
+#define SST_SST49LF040B                0x50
+#define SST_SST49LF040         0x51
+#define SST_SST49LF020         0x61
+#define SST_SST49LF020A                0x52
+#define SST_SST49LF030A                0x1C
+#define SST_SST49LF080A                0x5B
+#define SST_SST49LF002A                0x57
+#define SST_SST49LF003A                0x1B
+#define SST_SST49LF004A                0x60    /* Same as 49LF004B */
+#define SST_SST49LF008A                0x5A
+#define SST_SST49LF004C                0x54
+#define SST_SST49LF008C                0x59
+#define SST_SST49LF016C                0x5C
+#define SST_SST49LF160C                0x4C
+
+/*
+ * ST25P chips are SPI, first byte of device ID is memory type, second
+ * byte of device ID is related to log(bitsize) at least for some chips.
+ */
+#define ST_ID                  0x20    /* ST / SGS/Thomson / Numonyx (later acquired by Micron) */
+#define ST_M25P05A             0x2010
+#define ST_M25P05_RES          0x10    /* Same code as M25P10. */
+#define ST_M25P10A             0x2011
+#define ST_M25P10_RES          0x10    /* Same code as M25P05. */
+#define ST_M25P20              0x2012
+#define ST_M25P40              0x2013
+#define ST_M25P40_RES          0x12
+#define ST_M25P80              0x2014
+#define ST_M25P16              0x2015
+#define ST_M25P32              0x2016
+#define ST_M25P64              0x2017
+#define ST_M25P128             0x2018
+#define ST_M25PX16             0x7115
+#define ST_M25PX32             0x7116
+#define ST_M25PX64             0x7117
+#define ST_M25PE10             0x8011
+#define ST_M25PE20             0x8012
+#define ST_M25PE40             0x8013
+#define ST_M25PE80             0x8014
+#define ST_M25PE16             0x8015
+#define ST_M50FLW040A          0x08
+#define ST_M50FLW040B          0x28
+#define ST_M50FLW080A          0x80
+#define ST_M50FLW080B          0x81
+#define ST_M50FW002            0x29
+#define ST_M50FW040            0x2C
+#define ST_M50FW080            0x2D
+#define ST_M50FW016            0x2E
+#define ST_M50LPW116           0x30
+#define ST_M29F002B            0x34    /* Same as M29F002BB */
+#define ST_M29F002T            0xB0    /* Same as M29F002BT/M29F002NT/M29F002BNT */
+#define ST_M29F040B            0xE2    /* Same as M29F040 */
+#define ST_M29F080             0xF1
+#define ST_M29F200BT           0xD3
+#define ST_M29F200BB           0xD4
+#define ST_M29F400BT           0xD5    /* Same as M29F400T */
+#define ST_M29F400BB           0xD6    /* Same as M29F400B */
+#define ST_M29F800DB           0x58
+#define ST_M29F800DT           0xEC
+#define ST_M29W010B            0x23
+#define ST_M29W040B            0xE3
+#define ST_M29W512B            0x27
+#define ST_N25Q064             0xBA17
+
+#define SYNCMOS_MVC_ID         0x40    /* SyncMOS (SM) and Mosel Vitelic Corporation (MVC) */
+#define MVC_V29C51000T         0x00
+#define MVC_V29C51400T         0x13
+#define MVC_V29LC51000         0x20
+#define MVC_V29LC51001         0x60
+#define MVC_V29LC51002         0x82
+#define MVC_V29C51000B         0xA0
+#define MVC_V29C51400B         0xB3
+#define SM_MVC_29C51001T       0x01    /* Identical chips: {F,S,V}29C51001T */
+#define SM_MVC_29C51002T       0x02    /* Identical chips: {F,S,V}29C51002T */
+#define SM_MVC_29C51004T       0x03    /* Identical chips: {F,S,V}29C51004T */
+#define SM_MVC_29C31004T       0x63    /* Identical chips: {S,V}29C31004T */
+#define SM_MVC_29C31004B       0x73    /* Identical chips: {S,V}29C31004B */
+#define SM_MVC_29C51001B       0xA1    /* Identical chips: {F,S,V}29C51001B */
+#define SM_MVC_29C51002B       0xA2    /* Identical chips: {F,S,V}29C51002B */
+#define SM_MVC_29C51004B       0xA3    /* Identical chips: {F,S,V}29C51004B */
+
+#define TI_ID                  0x97    /* Texas Instruments */
+#define TI_OLD_ID              0x01    /* TI chips from last century */
+#define TI_TMS29F002RT         0xB0
+#define TI_TMS29F002RB         0x34
+
+/*
+ * W25X chips are SPI, first byte of device ID is memory type, second
+ * byte of device ID is related to log(bitsize).
+ */
+#define WINBOND_NEX_ID         0xEF    /* Winbond (ex Nexcom) serial flashes */
+#define WINBOND_NEX_W25X10     0x3011
+#define WINBOND_NEX_W25X20     0x3012
+#define WINBOND_NEX_W25X40     0x3013
+#define WINBOND_NEX_W25X80     0x3014
+#define WINBOND_NEX_W25X16     0x3015
+#define WINBOND_NEX_W25X32     0x3016
+#define WINBOND_NEX_W25X64     0x3017
+#define WINBOND_NEX_W25Q40     0x4013
+#define WINBOND_NEX_W25Q80     0x4014
+#define WINBOND_NEX_W25Q16     0x4015
+#define WINBOND_NEX_W25Q32     0x4016
+#define WINBOND_NEX_W25Q64     0x4017
+#define WINBOND_NEX_W25Q128    0x4018
+
+#define WINBOND_ID             0xDA    /* Winbond */
+#define WINBOND_W19B160BB      0x49
+#define WINBOND_W19B160BT      0xC4
+#define WINBOND_W19B320SB      0x2A    /* Same as W19L320SB */
+#define WINBOND_W19B320ST      0xBA    /* Same as W19L320ST */
+#define WINBOND_W19B322MB      0x92
+#define WINBOND_W19B322MT      0x10
+#define WINBOND_W19B323MB      0x94
+#define WINBOND_W19B323MT      0x13
+#define WINBOND_W19B324MB      0x97
+#define WINBOND_W19B324MT      0x16
+#define WINBOND_W29C010                0xC1    /* Same as W29C010M, W29C011A, W29EE011, W29EE012, and ASD AE29F1008 */
+#define WINBOND_W29C020                0x45    /* Same as W29C020C, W29C022 and ASD AE29F2008 */
+#define WINBOND_W29C040                0x46    /* Same as W29C040P */
+#define WINBOND_W29C512A       0xC8    /* Same as W29EE512 */
+#define WINBOND_W39L010                0x31
+#define WINBOND_W39L020                0xB5
+#define WINBOND_W39L040                0xB6
+#define WINBOND_W39L040A       0xD6
+#define WINBOND_W39L512                0x38
+#define WINBOND_W39V040A       0x3D
+#define WINBOND_W39V040FA      0x34
+#define WINBOND_W39V040B       0x54    /* Same as W39V040FB */
+#define WINBOND_W39V040C       0x50    /* Same as W39V040FC */
+#define WINBOND_W39V080A       0xD0
+#define WINBOND_W39V080FA      0xD3
+#define WINBOND_W39V080FA_DM   0x93    /* W39V080FA dual mode */
+#define WINBOND_W49F002                0x25    /* Same as W49F002B */
+#define WINBOND_W49F002U       0x0B    /* Same as W49F002N and ASD AE49F2008 */
+#define WINBOND_W49F020                0x8C
+#define WINBOND_W49V002A       0xB0
+#define WINBOND_W49V002FA      0x32
+
+#endif /* !FLASHCHIPS_H */
diff --git a/flashrom.8 b/flashrom.8
new file mode 100644 (file)
index 0000000..93df1a2
--- /dev/null
@@ -0,0 +1,930 @@
+.TH FLASHROM 8 "Feb 15, 2012"
+.SH NAME
+flashrom \- detect, read, write, verify and erase flash chips
+.SH SYNOPSIS
+.B flashrom \fR[\fB\-h\fR|\fB\-R\fR|\fB\-L\fR|\fB\-z\fR|\
+\fB\-p\fR <programmername>[:<parameters>]
+               [\fB\-E\fR|\fB\-r\fR <file>|\fB\-w\fR <file>|\fB\-v\fR <file>] \
+[\fB\-c\fR <chipname>]
+               [\fB\-l\fR <file> [\fB\-i\fR <image>]] [\fB\-n\fR] [\fB\-f\fR]]
+         [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>]
+.SH DESCRIPTION
+.B flashrom
+is a utility for detecting, reading, writing, verifying and erasing flash
+chips. It's often used to flash BIOS/EFI/coreboot/firmware images in-system
+using a supported mainboard. However, it also supports various external
+PCI/USB/parallel-port/serial-port based devices which can program flash chips,
+including some network cards (NICs), SATA/IDE controller cards, graphics cards,
+the Bus Pirate device, various FTDI FT2232/FT4232H based USB devices, and more.
+.PP
+It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, TSOP40,
+TSOP48, and BGA chips, which use various protocols such as LPC, FWH,
+parallel flash, or SPI.
+.SH OPTIONS
+.B IMPORTANT:
+Please note that the command line interface for flashrom will change before
+flashrom 1.0. Do not use flashrom in scripts or other automated tools without
+checking that your flashrom version won't interpret options in a different way.
+.PP
+You can specify one of
+.BR \-h ", " \-R ", " \-L ", " \-z ", " \-E ", " \-r ", " \-w ", " \-v
+or no operation.
+If no operation is specified, flashrom will only probe for flash chips. 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
+.B \-r
+before you try to write a new image.
+.TP
+.B "\-r, \-\-read <file>"
+Read flash ROM contents and save them into the given
+.BR <file> .
+If the file already exists, it will be overwritten.
+.TP
+.B "\-w, \-\-write <file>"
+Write
+.B <file>
+into flash ROM. This will first automatically
+.B erase
+the chip, then write to it.
+.sp
+In the process the chip is also read several times. First an in-memory backup
+is made for disaster recovery and to be able to skip regions that are
+already equal to the image file. This copy is updated along with the write
+operation. In case of erase errors it is even re-read completely. After
+writing has finished and if verification is enabled, the whole flash chip is
+read out and compared with the input image.
+.TP
+.B "\-n, \-\-noverify"
+Skip the automatic verification of flash ROM contents after writing. Using this
+option is
+.B not
+recommended, you should only use it if you know what you are doing and if you
+feel that the time for verification takes too long.
+.sp
+Typical usage is:
+.B "flashrom \-p prog \-n \-w <file>"
+.sp
+This option is only useful in combination with
+.BR \-\-write .
+.TP
+.B "\-v, \-\-verify <file>"
+Verify the flash ROM contents against the given
+.BR <file> .
+.TP
+.B "\-E, \-\-erase"
+Erase the flash ROM chip.
+.TP
+.B "\-V, \-\-verbose"
+More verbose output. This option can be supplied multiple times
+(max. 3 times, i.e.
+.BR \-VVV )
+for even more debug output.
+.TP
+.B "\-c, \-\-chip" <chipname>
+Probe only for the specified flash ROM chip. This option takes the chip name as
+printed by
+.B "flashrom \-L"
+without the vendor name as parameter. Please note that the chip name is
+case sensitive.
+.TP
+.B "\-f, \-\-force"
+Force one or more of the following actions:
+.sp
+* Force chip read and pretend the chip is there.
+.sp
+* Force chip access even if the chip is bigger than the maximum supported \
+size for the flash bus.
+.sp
+* Force erase even if erase is known bad.
+.sp
+* Force write even if write is known bad.
+.TP
+.B "\-l, \-\-layout <file>"
+Read ROM layout from
+.BR <file> .
+.sp
+flashrom supports ROM layouts. This allows you to flash certain parts of
+the flash chip only. A ROM layout file contains multiple lines with the
+following syntax:
+.sp
+.B "  startaddr:endaddr imagename"
+.sp
+.BR "startaddr " "and " "endaddr "
+are hexadecimal addresses within the ROM file and do not refer to any
+physical address. Please note that using a 0x prefix for those hexadecimal
+numbers is not necessary, but you can't specify decimal/octal numbers.
+.BR "imagename " "is an arbitrary name for the region/image from"
+.BR " startaddr " "to " "endaddr " "(both addresses included)."
+.sp
+Example:
+.sp
+  00000000:00008fff gfxrom
+  00009000:0003ffff normal
+  00040000:0007ffff fallback
+.sp
+If you only want to update the image named
+.BR "normal " "in a ROM based on the layout above, run"
+.sp
+.B "  flashrom \-p prog \-\-layout rom.layout \-\-image normal \-w some.rom"
+.sp
+To update only the images named 
+.BR "normal " "and " "fallback" ", run:"
+.sp
+.B "  flashrom \-p prog \-l rom.layout \-i normal -i fallback \-w some.rom"
+.sp
+Overlapping sections are not supported.
+.TP
+.B "\-i, \-\-image <imagename>"
+Only flash region/image
+.B <imagename>
+from flash layout.
+.TP
+.B "\-L, \-\-list\-supported"
+List the flash chips, chipsets, mainboards, and external programmers
+(including PCI, USB, parallel port, and serial port based devices)
+supported by flashrom.
+.sp
+There are many unlisted boards which will work out of the box, without
+special support in flashrom. Please let us know if you can verify that
+other boards work or do not work out of the box.
+.sp
+.B IMPORTANT:
+For verification you have
+to test an ERASE and/or WRITE operation, so make sure you only do that
+if you have proper means to recover from failure!
+.TP
+.B "\-z, \-\-list\-supported-wiki"
+Same as
+.BR \-\-list\-supported ,
+but outputs the supported hardware in MediaWiki syntax, so that it can be
+easily pasted into the wiki page at
+.BR http://www.flashrom.org/ .
+Please note that MediaWiki output is not compiled in by default.
+.TP
+.B "\-p, \-\-programmer <name>[:parameter[,parameter[,parameter]]]"
+Specify the programmer device. This is mandatory for all operations
+involving any chip access (probe/read/write/...). Currently supported are:
+.sp
+.BR "* internal" " (default, for in-system flashing in the mainboard)"
+.sp
+.BR "* dummy" " (virtual programmer for testing flashrom)"
+.sp
+.BR "* nic3com" " (for flash ROMs on 3COM network cards)"
+.sp
+.BR "* nicrealtek" " (for flash ROMs on Realtek network cards)"
+.sp
+.BR "* nicsmc1211" " (for flash ROMs on RTL8139-compatible SMC2 network cards)"
+.sp
+.BR "* nicnatsemi" " (for flash ROMs on National Semiconductor DP838* network \
+cards)"
+.sp
+.BR "* nicintel" " (for parallel flash ROMs on Intel 10/100Mbit 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 "* satamv" " (for flash ROMs on Marvell SATA controllers)"
+.sp
+.BR "* atahpt" " (for flash ROMs on Highpoint ATA/RAID controllers)"
+.sp
+.BR "* ft2232_spi" " (for SPI flash ROMs attached to an FT2232/FT4232H family \
+based USB SPI programmer), including the DLP Design DLP-USB1232H, \
+FTDI FT2232H Mini-Module, FTDI FT4232H Mini-Module, openbiosprog-spi, Amontec \
+JTAGkey/JTAGkey-tiny/JTAGkey-2, Dangerous Prototypes Bus Blaster, \
+Olimex ARM-USB-TINY/-H, Olimex ARM-USB-OCD/-H, TIAO/DIYGADGET USB
+Multi-Protocol Adapter (TUMPA), and GOEPEL PicoTAP.
+.sp
+.BR "* serprog" " (for flash ROMs attached to a programmer speaking serprog), \
+including AVR flasher by Urja Rannikko, AVR flasher by eightdot, \
+Arduino Mega flasher by fritz, InSystemFlasher by Juhana Helovuo, and \
+atmegaXXu2-flasher by Stefan Tauner."
+.sp
+.BR "* buspirate_spi" " (for SPI flash ROMs attached to a Bus Pirate)"
+.sp
+.BR "* dediprog" " (for SPI flash ROMs attached to a Dediprog SF100)"
+.sp
+.BR "* rayer_spi" " (for SPI flash ROMs attached to a RayeR parport "
+or Xilinx DLC5 compatible cable)
+.sp
+.BR "* pony_spi" " (for SPI flash ROMs attached to a SI-Prog serial port "
+bitbanging adapter)
+.sp
+.BR "* nicintel_spi" " (for SPI flash ROMs on Intel Gigabit network cards)"
+.sp
+.BR "* ogp_spi" " (for SPI flash ROMs on Open Graphics Project graphics card)"
+.sp
+.BR "* linux_spi" " (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)"
+.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 "\-o, \-\-output <logfile>"
+Save the full debug log to
+.BR <logfile> .
+If the file already exists, it will be overwritten. This is the recommended
+way to gather logs from flashrom because they will be verbose even if the
+on-screen messages are not verbose.
+.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.
+.SS
+.BR "internal " programmer
+.TP
+.B Board Enables
+.sp
+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), or if you want to override
+the detected mainboard model, you can specify the mainboard using the
+.sp
+.B "  flashrom \-p internal:mainboard=[<vendor>:]<board>"
+syntax.
+.sp
+See the 'Known boards' or 'Known laptops' 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.
+.sp
+Some of these board-specific flash enabling functions (called
+.BR "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
+.BR \-r )
+and store it to a medium outside of your computer, like
+a 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
+.TP
+.B Coreboot
+.sp
+On systems running coreboot, flashrom checks whether the desired image matches
+your mainboard. This needs some special board ID to be present in the image.
+If flashrom detects that the image you want to write and the current board
+do not match, it will refuse to write the image unless you specify
+.sp
+.B "  flashrom \-p internal:boardmismatch=force"
+.TP
+.B ITE IT87 Super I/O
+.sp
+If your mainboard uses an ITE IT87 series Super I/O for LPC<->SPI flash bus
+translation, flashrom should autodetect that configuration. If you want to
+set the I/O base port of the IT87 series SPI controller manually instead of
+using the value provided by the BIOS, use the
+.sp
+.B "  flashrom \-p internal:it87spiport=portnum"
+.sp
+syntax where
+.B portnum
+is the I/O port number (must be a multiple of 8). In the unlikely case
+flashrom doesn't detect an active IT87 LPC<->SPI bridge, please send a bug
+report so we can diagnose the problem.
+.sp
+.TP
+.B Intel chipsets
+.sp
+If you have an Intel chipset with an ICH8 or later southbridge with SPI flash
+attached, and if a valid descriptor was written to it (e.g. by the vendor), the
+chipset provides an alternative way to access the flash chip(s) named
+.BR "Hardware Sequencing" .
+It is much simpler than the normal access method (called
+.BR "Software Sequencing" "),"
+but does not allow the software to choose the SPI commands to be sent.
+You can use the
+.sp
+.B "  flashrom \-p internal:ich_spi_mode=value"
+.sp
+syntax where
+.BR "value " "can be"
+.BR auto ", " swseq " or " hwseq .
+By default
+.RB "(or when setting " ich_spi_mode=auto )
+the module tries to use swseq and only activates hwseq if need be (e.g. if
+important opcodes are inaccessible due to lockdown; or if more than one flash
+chip is attached). The other options (swseq, hwseq) select the respective mode
+(if possible).
+.sp
+ICH8 and later southbridges may also have locked address ranges of different
+kinds if a valid descriptor was written to it. The flash address space is then
+partitioned in multiple so called "Flash Regions" containing the host firmware,
+the ME firmware and so on respectively. The flash descriptor can also specify up
+to 5 so called "Protected Regions", which are freely chosen address ranges
+independent from the aforementioned "Flash Regions". All of them can be write
+and/or read protected individually. If flashrom detects such a lock it will
+disable write support unless the user forces it with the
+.sp
+.B "  flashrom \-p internal:ich_spi_force=yes"
+.sp
+syntax. If this leads to erase or write accesses to the flash it would most
+probably bring it into an inconsistent and unbootable state and we will not
+provide any support in such a case.
+.sp
+If you have an Intel chipset with an ICH6 or later southbridge and if you want
+to set specific IDSEL values for a non-default flash chip or an embedded
+controller (EC), you can use the
+.sp
+.B "  flashrom \-p internal:fwh_idsel=value"
+.sp
+syntax where
+.B value
+is the 48-bit hexadecimal raw value to be written in the
+IDSEL registers of the Intel southbridge. The upper 32 bits use one hex digit
+each per 512 kB range between 0xffc00000 and 0xffffffff, and the lower 16 bits
+use one hex digit each per 1024 kB range between 0xff400000 and 0xff7fffff.
+The rightmost hex digit corresponds with the lowest address range. All address
+ranges have a corresponding sister range 4 MB below with identical IDSEL
+settings. The default value for ICH7 is given in the example below.
+.sp
+Example:
+.B "flashrom \-p internal:fwh_idsel=0x001122334567"
+.TP
+.B Laptops
+.sp
+Using flashrom on laptops is dangerous and may easily make your hardware
+unusable (see also the
+.B BUGS
+section). The embedded controller (EC) in these
+machines often interacts badly with flashing.
+.B http://www.flashrom.org/Laptops
+has more information. For example the EC firmware sometimes resides on the same
+flash chip as the host firmware. While flashrom tries to change the contents of
+that memory the EC might need to fetch new instructions or data from it and
+could stop working correctly. Probing for and reading from the chip may also
+irritate your EC and cause fan failure, backlight failure, sudden poweroff, and
+other nasty effects. flashrom will attempt to detect if it is running on a
+laptop and abort immediately for safety reasons if it clearly identifies the
+host computer as one. If you want to proceed anyway at your own risk, use
+.sp
+.B "  flashrom \-p internal:laptop=force_I_want_a_brick"
+.sp
+We will not help you if you force flashing on a laptop because this is a really
+dumb idea.
+.sp
+You have been warned.
+.sp
+Currently we rely on the chassis type encoded in the DMI/SMBIOS data to detect
+laptops. Some vendors did not implement those bits correctly or set them to
+generic and/or dummy values. flashrom will then issue a warning and bail out
+like above. In this case you can use
+.sp
+.B "  flashrom \-p internal:laptop=this_is_not_a_laptop"
+.sp
+to tell flashrom (at your own risk) that it does not running on a laptop.
+.SS
+.BR "dummy " programmer
+The dummy programmer operates on a buffer in memory only. It provides a safe
+and fast way to test various aspects of flashrom and is mainly used in
+development and while debugging.
+.sp
+It is able to emulate some chips to a certain degree (basic
+identify/read/erase/write operations work).
+.sp
+An optional parameter specifies the bus types it
+should support. For that you have to use the
+.sp
+.B "  flashrom \-p dummy:bus=[type[+type[+type]]]"
+.sp
+syntax where
+.B type
+can be
+.BR parallel ", " lpc ", " fwh ", " spi
+in any order. If you specify bus without type, all buses will be disabled.
+If you do not specify bus, all buses will be enabled.
+.sp
+Example:
+.B "flashrom \-p dummy:bus=lpc+fwh"
+.sp
+The dummy programmer supports flash chip emulation for automated self-tests
+without hardware access. If you want to emulate a flash chip, use the
+.sp
+.B "  flashrom \-p dummy:emulate=chip"
+.sp
+syntax where
+.B chip
+is one of the following chips (please specify only the chip name, not the
+vendor):
+.sp
+.RB "* ST " M25P10.RES " SPI flash chip (RES, page write)"
+.sp
+.RB "* SST " SST25VF040.REMS " SPI flash chip (REMS, byte write)"
+.sp
+.RB "* SST " SST25VF032B " SPI flash chip (RDID, AAI write)"
+.sp
+.RB "* Macronix " MX25L6436 " SPI flash chip (RDID, SFDP)"
+.sp
+Example:
+.B "flashrom -p dummy:emulate=SST25VF040.REMS"
+.TP
+.B Persistent images
+.sp
+If you use flash chip emulation, flash image persistence is available as well
+by using the
+.sp
+.B "  flashrom \-p dummy:emulate=chip,image=image.rom"
+.sp
+syntax where
+.B image.rom
+is the file where the simulated chip contents are read on flashrom startup and
+where the chip contents on flashrom shutdown are written to.
+.sp
+Example:
+.B "flashrom -p dummy:emulate=M25P10.RES,image=dummy.bin"
+.TP
+.B SPI write chunk size
+.sp
+If you use SPI flash chip emulation for a chip which supports SPI page write
+with the default opcode, you can set the maximum allowed write chunk size with
+the
+.sp
+.B "  flashrom \-p dummy:emulate=chip,spi_write_256_chunksize=size"
+.sp
+syntax where
+.B size
+is the number of bytes (min. 1, max. 256).
+.sp
+Example:
+.sp
+.B "  flashrom -p dummy:emulate=M25P10.RES,spi_write_256_chunksize=5"
+.TP
+.B SPI blacklist
+.sp
+To simulate a programmer which refuses to send certain SPI commands to the
+flash chip, you can specify a blacklist of SPI commands with the
+.sp
+.B "  flashrom -p dummy:spi_blacklist=commandlist"
+.sp
+syntax where
+.B commandlist
+is a list of two-digit hexadecimal representations of
+SPI commands. If commandlist is e.g. 0302, flashrom will behave as if the SPI
+controller refuses to run command 0x03 (READ) and command 0x02 (WRITE).
+commandlist may be up to 512 characters (256 commands) long.
+Implementation note: flashrom will detect an error during command execution.
+.sp
+.TP
+.B SPI ignorelist
+.sp
+To simulate a flash chip which ignores (doesn't support) certain SPI commands,
+you can specify an ignorelist of SPI commands with the
+.sp
+.B "  flashrom -p dummy:spi_ignorelist=commandlist"
+.sp
+syntax where
+.B commandlist
+is a list of two-digit hexadecimal representations of
+SPI commands. If commandlist is e.g. 0302, the emulated flash chip will ignore
+command 0x03 (READ) and command 0x02 (WRITE).  commandlist may be up to 512
+characters (256 commands) long.
+Implementation note: flashrom won't detect an error during command execution.
+.sp
+.TP
+.B SPI status register
+.sp
+You can specify the initial content of the chip's status register with the
+.sp
+.B "  flashrom -p dummy:spi_status=content"
+.sp
+syntax where
+.B content
+is an 8-bit hexadecimal value.
+.SS
+.BR "nic3com" , " nicrealtek" , " nicsmc1211" , " nicnatsemi" , " nicintel\
+" , " nicintel_spi" , " gfxnvidia" , " ogp_spi" , " drkaiser" , " satasii\
+" , " satamv" ", 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
+.sp
+.BR "  flashrom \-p xxxx:pci=bb:dd.f" ,
+.sp
+where
+.B xxxx
+is the name of the programmer
+.B bb
+is the PCI bus number,
+.B dd
+is the PCI device number, and
+.B f
+is the PCI function number of the desired device.
+.sp
+Example:
+.B "flashrom \-p nic3com:pci=05:04.0"
+.SS
+.BR "ft2232_spi " programmer
+An optional parameter specifies the controller
+type and interface/port it should support. For that you have to use the
+.sp
+.B "  flashrom \-p ft2232_spi:type=model,port=interface"
+.sp
+syntax where
+.B model
+can be
+.BR 2232H ", " 4232H ", " jtagkey ", " busblaster ", " openmoko ", " \
+arm-usb-tiny ", " arm-usb-tiny-h ", " arm-usb-ocd ", " arm-usb-ocd-h \
+", " tumpa ", or " picotap
+and
+.B interface
+can be
+.BR A ", or " B .
+The default model is
+.B 4232H
+and the default interface is
+.BR B .
+.sp
+All models supported by the ft2232_spi driver can configure the SPI clock rate by setting a divisor. The
+expressible divisors are all even numbers between 2 and 2^17 (=131072) resulting in SPI clock frequencies of
+6 MHz down to about 92 Hz for 12 MHz inputs. The default divisor is set to 2, but you can use another one by
+specifying the optional
+.B divisor
+parameter with the
+.sp
+.B "  flashrom \-p ft2232_spi:divisor=div"
+.sp
+syntax.
+.SS
+.BR "serprog " programmer
+A mandatory parameter specifies either a serial
+device/baud combination or an IP/port combination for communication with the
+programmer. In the device/baud combination, the device has to start with a
+slash. For serial, you have to use the
+.sp
+.B "  flashrom \-p serprog:dev=/dev/device:baud"
+.sp
+syntax and for IP, you have to use
+.sp
+.B "  flashrom \-p serprog:ip=ipaddr:port"
+.sp
+instead. More information about serprog is available in
+.B serprog-protocol.txt
+in the source distribution.
+.SS
+.BR "buspirate_spi " programmer
+A required
+.B dev
+parameter specifies the Bus Pirate device node and an optional
+.B spispeed
+parameter specifies the frequency of the SPI bus. The parameter
+delimiter is a comma. Syntax is
+.sp
+.B "  flashrom \-p buspirate_spi:dev=/dev/device,spispeed=frequency"
+.sp
+where
+.B frequency
+can be
+.BR 30k ", " 125k ", " 250k ", " 1M ", " 2M ", " 2.6M ", " 4M " or " 8M
+(in Hz). The default is the maximum frequency of 8 MHz.
+.SS
+.BR "dediprog " programmer
+An optional
+.B voltage
+parameter specifies the voltage the Dediprog should use. The default unit is
+Volt if no unit is specified. You can use
+.BR mV ", " milliVolt ", " V " or " Volt
+as unit specifier. Syntax is
+.sp
+.B "  flashrom \-p dediprog:voltage=value"
+.sp
+where
+.B value
+can be
+.BR 0V ", " 1.8V ", " 2.5V ", " 3.5V
+or the equivalent in mV.
+.SS
+.BR "rayer_spi " programmer
+The default I/O base address used for the parallel port is 0x378 and you can use
+the optional
+.B iobase
+parameter to specify an alternate base I/O address with the
+.sp
+.B "  flashrom \-p rayer_spi:iobase=baseaddr"
+.sp
+syntax where
+.B baseaddr
+is base I/O port address of the parallel port, which must be a multiple of
+four. Make sure to not forget the "0x" prefix for hexadecimal port addresses.
+.sp
+The default cable type is the RayeR cable. You can use the optional
+.B type
+parameter to specify the cable type with the
+.sp
+.B "  flashrom \-p rayer_spi:type=model"
+.sp
+syntax where
+.B model
+can be
+.BR rayer " for the RayeR cable or " xilinx " for the Xilinx Parallel Cable III
+(DLC 5).
+.sp
+More information about the RayeR hardware is available at
+.BR "http://rayer.ic.cz/elektro/spipgm.htm " .
+The schematic of the Xilinx DLC 5 was published at
+.BR "http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html " .
+.SS
+.BR "pony_spi " programmer
+The serial port (like /dev/ttyS0, /dev/ttyUSB0 on Linux or COM3 on windows) is
+specified using the mandatory
+.B dev 
+parameter. The adapter type is selectable between SI-Prog (used for
+SPI devices with PonyProg 2000) or a custom made serial bitbanging programmer
+named "serbang". The optional
+.B type 
+parameter accepts the values "si_prog" (default) or "serbang".
+.sp
+Information about the SI-Prog adapter can be found at
+.BR "http://www.lancos.com/siprogsch.html " .
+.sp
+An example call to flashrom is
+.sp
+.B "  flashrom \-p pony_spi:dev=/dev/ttyS0,type=serbang"
+.sp
+Please note that while USB-to-serial adapters work under certain circumstances,
+this slows down operation considerably.
+.SS
+.BR "ogp_spi " programmer
+The flash ROM chip to access must be specified with the
+.B rom
+parameter.
+.sp
+.B "  flashrom \-p ogp_spi:rom=name"
+.sp
+Where
+.B name
+is either
+.B cprom
+or
+.B s3
+for the configuration ROM and 
+.B bprom
+or
+.B bios
+for the BIOS ROM. If more than one card supported by the ogp_spi programmer
+is installed in your system, you have to specify the PCI address of the card
+you want to use with the
+.B pci=
+parameter as explained in the
+.B nic3com
+section above.
+.sp
+More information about the hardware is available at
+.BR http://wiki.opengraphics.org .
+.SS
+.BR "linux_spi " programmer
+You have to specify the SPI controller to use with the
+.sp
+.B "  flashrom \-p linux_spi:dev=/dev/spidevX.Y"
+.sp
+syntax where
+.B /dev/spidevX.Y
+is the Linux device node for your SPI controller.
+.sp
+Please note that the linux_spi driver only works on Linux.
+.SH EXAMPLES
+To back up and update your BIOS, run
+.sp
+.B flashrom -p internal -r backup.rom -o backuplog.txt
+.br
+.B flashrom -p internal -w newbios.rom -o writelog.txt
+.sp
+Please make sure to copy backup.rom to some external media before you try
+to write. That makes offline recovery easier.
+.br
+If writing fails and flashrom complains about the chip being in an unknown
+state, you can try to restore the backup by running
+.sp
+.B flashrom -p internal -w backup.rom -o restorelog.txt
+.sp
+If you encounter any problems, please contact us and supply
+backuplog.txt, writelog.txt and restorelog.txt. See section
+.B BUGS
+for contact info.
+.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.
+.SH REQUIREMENTS
+flashrom needs different access permissions for different programmers.
+.sp
+.B internal
+needs raw memory access, PCI configuration space access, raw I/O port
+access (x86) and MSR access (x86).
+.sp
+.BR nic3com ", " nicrealtek ", " nicsmc1211 " and " nicnatsemi "
+need PCI configuration space read access and raw I/O port access.
+.sp
+.B atahpt
+needs PCI configuration space access and raw I/O port access.
+.sp
+.BR gfxnvidia " and " drkaiser
+need PCI configuration space access and raw memory access.
+.sp
+.B rayer_spi
+needs raw I/O port access.
+.sp
+.B satasii
+needs PCI configuration space read access and raw memory access.
+.sp
+.B satamv
+needs PCI configuration space read access, raw I/O port access and raw memory
+access.
+.sp
+.B serprog
+needs TCP access to the network or userspace access to a serial port.
+.sp
+.B buspirate_spi
+needs userspace access to a serial port.
+.sp
+.BR dediprog " and " ft2232_spi
+need access to the USB device via libusb.
+.sp
+.B dummy
+needs no access permissions at all.
+.sp
+.BR internal ", " nic3com ", " nicrealtek ", " nicsmc1211 ", " nicnatsemi ", "
+.BR gfxnvidia ", " drkaiser ", " satasii ", " satamv " and " atahpt
+have to be run as superuser/root, and need additional raw access permission.
+.sp
+.BR serprog ", " buspirate_spi ", " dediprog " and " ft2232_spi
+can be run as normal user on most operating systems if appropriate device
+permissions are set.
+.sp
+.B ogp
+needs PCI configuration space read access and raw memory access.
+.sp
+On OpenBSD, you can obtain raw access permission by setting
+.B "securelevel=-1"
+in
+.B "/etc/rc.securelevel"
+and rebooting, or rebooting into single user mode.
+.SH BUGS
+Please report any bugs to the flashrom mailing list at
+.B "<flashrom@flashrom.org>"
+.sp
+We recommend to subscribe first at
+.sp
+.B "  http://www.flashrom.org/mailman/listinfo/flashrom"
+.sp
+Many of the developers communicate via the
+.B "#flashrom"
+IRC channel on
+.BR chat.freenode.net .
+You are welcome to join and ask questions, send us bug and success reports there
+too. Please provide a way to contact you later (e.g. a mail address) and be
+patient if there is no immediate reaction. Also, we provide a pastebin service
+at
+.B http://paste.flashrom.org
+that is very useful when you want to share logs etc. without spamming the
+channel.
+.SS
+.B Laptops
+.sp
+Using flashrom on laptops is dangerous and may easily make your hardware
+unusable. flashrom will attempt to detect if it is running on a laptop and abort
+immediately for safety reasons. Please see the detailed discussion of this topic
+and associated flashrom options in the
+.B Laptops
+paragraph in the
+.B internal programmer
+subsection of the
+.B PROGRAMMER SPECIFIC INFO
+section.
+.B "  http://www.flashrom.org/Laptops"
+.SS
+One-time programmable (OTP) memory and unique IDs
+.sp
+Some flash chips contain OTP memory often denoted as "security registers".
+They usually have a capacity in the range of some bytes to a few hundred
+bytes and can be used to give devices unique IDs etc. flashrom is not able
+to read or write these memories and may therefore not be able to duplicate a
+chip completely. For chip types known to include OTP memories a warning is
+printed when they are detected.
+.sp
+Similar to OTP memories are unique, factory programmed, unforgeable IDs.
+They are not modifiable by the user at all.
+.SH LICENSE
+.B flashrom
+is covered by the GNU General Public License (GPL), version 2. Some files are
+additionally available under the GPL (version 2, or any later version).
+.SH COPYRIGHT
+.br
+Please see the individual files.
+.SH AUTHORS
+Andrew Morgan
+.br
+Carl-Daniel Hailfinger
+.br
+Claus Gindhart
+.br
+David Borg
+.br
+David Hendricks
+.br
+Dominik Geyer
+.br
+Eric Biederman
+.br
+Giampiero Giancipoli
+.br
+Helge Wagner
+.br
+Idwer Vollering
+.br
+Joe Bao
+.br
+Joerg Fischer
+.br
+Joshua Roys
+.br
+Luc Verhaegen
+.br
+Li-Ta Lo
+.br
+Mark Marshall
+.br
+Markus Boas
+.br
+Mattias Mattsson
+.br
+Michael Karcher
+.br
+Nikolay Petukhov
+.br
+Patrick Georgi
+.br
+Peter Lemenkov
+.br
+Peter Stuge
+.br
+Reinder E.N. de Haan
+.br
+Ronald G. Minnich
+.br
+Ronald Hoogenboom
+.br
+Sean Nelson
+.br
+Stefan Reinauer
+.br
+Stefan Tauner
+.br
+Stefan Wildemann
+.br
+Stephan Guilloux
+.br
+Steven James
+.br
+Uwe Hermann
+.br
+Wang Qingpei
+.br
+Yinghai Lu
+.br
+some others, please see the flashrom svn changelog for details.
+.br
+All authors can be reached via email at <flashrom@flashrom.org>.
+.PP
+This manual page was written by Uwe Hermann <uwe@hermann-uwe.de>,
+Carl-Daniel Hailfinger and others.
+It is licensed under the terms of the GNU GPL (version 2 or later).
diff --git a/flashrom.c b/flashrom.c
new file mode 100644 (file)
index 0000000..04e9934
--- /dev/null
@@ -0,0 +1,1861 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
+ * Copyright (C) 2005-2008 coresystems GmbH
+ * Copyright (C) 2008,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 <stdio.h>
+#include <sys/types.h>
+#ifndef __LIBPAYLOAD__
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <getopt.h>
+#if HAVE_UTSNAME == 1
+#include <sys/utsname.h>
+#endif
+#include "flash.h"
+#include "flashchips.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+const char flashrom_version[] = FLASHROM_VERSION;
+char *chip_to_probe = NULL;
+int verbose_screen = MSG_INFO;
+int verbose_logfile = MSG_DEBUG2;
+
+static enum programmer programmer = PROGRAMMER_INVALID;
+
+static char *programmer_param = NULL;
+
+/*
+ * 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;
+
+/* If nonzero, used as the start address of bottom-aligned flash. */
+unsigned long flashbase;
+
+/* Is writing allowed with this programmer? */
+int programmer_may_write;
+
+#if CONFIG_INTERNAL+CONFIG_DUMMY+CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_FT2232_SPI+CONFIG_SERPROG+CONFIG_BUSPIRATE_SPI+CONFIG_DEDIPROG+CONFIG_RAYER_SPI+CONFIG_PONY_SPI+CONFIG_NICINTEL+CONFIG_NICINTEL_SPI+CONFIG_OGP_SPI+CONFIG_SATAMV+CONFIG_LINUX_SPI < 1
+#error You have to enable at least one programmer!
+#endif
+
+const struct programmer_entry programmer_table[] = {
+#if CONFIG_INTERNAL == 1
+       {
+               .name                   = "internal",
+               .init                   = internal_init,
+               .map_flash_region       = physmap,
+               .unmap_flash_region     = physunmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_DUMMY == 1
+       {
+               .name                   = "dummy",
+               .init                   = dummy_init,
+               .map_flash_region       = dummy_map,
+               .unmap_flash_region     = dummy_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_NIC3COM == 1
+       {
+               .name                   = "nic3com",
+               .init                   = nic3com_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_NICREALTEK == 1
+       {
+               /* This programmer works for Realtek RTL8139 and SMC 1211. */
+               .name                   = "nicrealtek",
+               //.name                 = "nicsmc1211",
+               .init                   = nicrealtek_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_NICNATSEMI == 1
+       {
+               .name                   = "nicnatsemi",
+               .init                   = nicnatsemi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_GFXNVIDIA == 1
+       {
+               .name                   = "gfxnvidia",
+               .init                   = gfxnvidia_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_DRKAISER == 1
+       {
+               .name                   = "drkaiser",
+               .init                   = drkaiser_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_SATASII == 1
+       {
+               .name                   = "satasii",
+               .init                   = satasii_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_ATAHPT == 1
+       {
+               .name                   = "atahpt",
+               .init                   = atahpt_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_FT2232_SPI == 1
+       {
+               .name                   = "ft2232_spi",
+               .init                   = ft2232_spi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_SERPROG == 1
+       {
+               .name                   = "serprog",
+               .init                   = serprog_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = serprog_delay,
+       },
+#endif
+
+#if CONFIG_BUSPIRATE_SPI == 1
+       {
+               .name                   = "buspirate_spi",
+               .init                   = buspirate_spi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_DEDIPROG == 1
+       {
+               .name                   = "dediprog",
+               .init                   = dediprog_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_RAYER_SPI == 1
+       {
+               .name                   = "rayer_spi",
+               .init                   = rayer_spi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_PONY_SPI == 1
+       {
+               .name                   = "pony_spi",
+               .init                   = pony_spi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+},
+#endif
+
+#if CONFIG_NICINTEL == 1
+       {
+               .name                   = "nicintel",
+               .init                   = nicintel_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_NICINTEL_SPI == 1
+       {
+               .name                   = "nicintel_spi",
+               .init                   = nicintel_spi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_OGP_SPI == 1
+       {
+               .name                   = "ogp_spi",
+               .init                   = ogp_spi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_SATAMV == 1
+       {
+               .name                   = "satamv",
+               .init                   = satamv_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+#if CONFIG_LINUX_SPI == 1
+       {
+               .name                   = "linux_spi",
+               .init                   = linux_spi_init,
+               .map_flash_region       = fallback_map,
+               .unmap_flash_region     = fallback_unmap,
+               .delay                  = internal_delay,
+       },
+#endif
+
+       {}, /* This entry corresponds to PROGRAMMER_INVALID. */
+};
+
+#define SHUTDOWN_MAXFN 32
+static int shutdown_fn_count = 0;
+struct shutdown_func_data {
+       int (*func) (void *data);
+       void *data;
+} static shutdown_fn[SHUTDOWN_MAXFN];
+/* Initialize to 0 to make sure nobody registers a shutdown function before
+ * programmer init.
+ */
+static int may_register_shutdown = 0;
+
+static int check_block_eraser(const struct flashctx *flash, int k, int log);
+
+/* 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(int (*function) (void *data), void *data)
+{
+       if (shutdown_fn_count >= SHUTDOWN_MAXFN) {
+               msg_perr("Tried to register more than %i shutdown functions.\n",
+                        SHUTDOWN_MAXFN);
+               return 1;
+       }
+       if (!may_register_shutdown) {
+               msg_perr("Tried to register a shutdown function before "
+                        "programmer init.\n");
+               return 1;
+       }
+       shutdown_fn[shutdown_fn_count].func = function;
+       shutdown_fn[shutdown_fn_count].data = data;
+       shutdown_fn_count++;
+
+       return 0;
+}
+
+int programmer_init(enum programmer prog, char *param)
+{
+       int ret;
+
+       if (prog >= PROGRAMMER_INVALID) {
+               msg_perr("Invalid programmer specified!\n");
+               return -1;
+       }
+       programmer = prog;
+       /* Initialize all programmer specific data. */
+       /* Default to unlimited decode sizes. */
+       max_rom_decode = (const struct decode_sizes) {
+               .parallel       = 0xffffffff,
+               .lpc            = 0xffffffff,
+               .fwh            = 0xffffffff,
+               .spi            = 0xffffffff,
+       };
+       /* Default to top aligned flash at 4 GB. */
+       flashbase = 0;
+       /* Registering shutdown functions is now allowed. */
+       may_register_shutdown = 1;
+       /* Default to allowing writes. Broken programmers set this to 0. */
+       programmer_may_write = 1;
+
+       programmer_param = param;
+       msg_pdbg("Initializing %s programmer\n",
+                programmer_table[programmer].name);
+       ret = programmer_table[programmer].init();
+       if (programmer_param && strlen(programmer_param)) {
+               msg_perr("Unhandled programmer parameters: %s\n",
+                        programmer_param);
+               /* Do not error out here, the init itself was successful. */
+       }
+       return ret;
+}
+
+int programmer_shutdown(void)
+{
+       int ret = 0;
+
+       /* Registering shutdown functions is no longer allowed. */
+       may_register_shutdown = 0;
+       while (shutdown_fn_count > 0) {
+               int i = --shutdown_fn_count;
+               ret |= shutdown_fn[i].func(shutdown_fn[i].data);
+       }
+       return ret;
+}
+
+void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
+                                 size_t len)
+{
+       return programmer_table[programmer].map_flash_region(descr,
+                                                            phys_addr, len);
+}
+
+void programmer_unmap_flash_region(void *virt_addr, size_t len)
+{
+       programmer_table[programmer].unmap_flash_region(virt_addr, len);
+}
+
+void chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+       flash->pgm->par.chip_writeb(flash, val, addr);
+}
+
+void chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
+{
+       flash->pgm->par.chip_writew(flash, val, addr);
+}
+
+void chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
+{
+       flash->pgm->par.chip_writel(flash, val, addr);
+}
+
+void chip_writen(const struct flashctx *flash, uint8_t *buf, chipaddr addr,
+                size_t len)
+{
+       flash->pgm->par.chip_writen(flash, buf, addr, len);
+}
+
+uint8_t chip_readb(const struct flashctx *flash, const chipaddr addr)
+{
+       return flash->pgm->par.chip_readb(flash, addr);
+}
+
+uint16_t chip_readw(const struct flashctx *flash, const chipaddr addr)
+{
+       return flash->pgm->par.chip_readw(flash, addr);
+}
+
+uint32_t chip_readl(const struct flashctx *flash, const chipaddr addr)
+{
+       return flash->pgm->par.chip_readl(flash, addr);
+}
+
+void chip_readn(const struct flashctx *flash, uint8_t *buf, chipaddr addr,
+               size_t len)
+{
+       flash->pgm->par.chip_readn(flash, buf, addr, len);
+}
+
+void programmer_delay(int usecs)
+{
+       programmer_table[programmer].delay(usecs);
+}
+
+void map_flash_registers(struct flashctx *flash)
+{
+       size_t size = flash->total_size * 1024;
+       /* Flash registers live 4 MByte below the flash. */
+       /* FIXME: This is incorrect for nonstandard flashbase. */
+       flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
+}
+
+int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start,
+                  int unsigned len)
+{
+       chip_readn(flash, buf, flash->virtual_memory + start, len);
+
+       return 0;
+}
+
+int min(int a, int b)
+{
+       return (a < b) ? a : b;
+}
+
+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;
+}
+
+void tolower_string(char *str)
+{
+       for (; *str != '\0'; str++)
+               *str = (char)tolower((unsigned char)*str);
+}
+
+char *strcat_realloc(char *dest, const char *src)
+{
+       dest = realloc(dest, strlen(dest) + strlen(src) + 1);
+       if (!dest) {
+               msg_gerr("Out of memory!\n");
+               return NULL;
+       }
+       strcat(dest, src);
+       return dest;
+}
+
+/* This is a somewhat hacked function similar in some ways to strtok().
+ * It will look for needle with a subsequent '=' 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, const char *needle, const char *delim)
+{
+       char *param_pos, *opt_pos, *rest;
+       char *opt = NULL;
+       int optlen;
+       int needlelen;
+
+       needlelen = strlen(needle);
+       if (!needlelen) {
+               msg_gerr("%s: empty needle! Please report a bug at "
+                        "flashrom@flashrom.org\n", __func__);
+               return NULL;
+       }
+       /* No programmer parameters given. */
+       if (*haystack == NULL)
+               return NULL;
+       param_pos = strstr(*haystack, needle);
+       do {
+               if (!param_pos)
+                       return NULL;
+               /* Needle followed by '='? */
+               if (param_pos[needlelen] == '=') {
+                       
+                       /* 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) {
+               /* Get the string after needle and '='. */
+               opt_pos = param_pos + needlelen + 1;
+               optlen = strcspn(opt_pos, delim);
+               /* Return an empty string if the parameter was empty. */
+               opt = malloc(optlen + 1);
+               if (!opt) {
+                       msg_gerr("Out of memory!\n");
+                       exit(1);
+               }
+               strncpy(opt, opt_pos, optlen);
+               opt[optlen] = '\0';
+               rest = opt_pos + optlen;
+               /* Skip all delimiters after the current parameter. */
+               rest += strspn(rest, delim);
+               memmove(param_pos, rest, strlen(rest) + 1);
+               /* We could shrink haystack, but the effort is not worth it. */
+       }
+
+       return opt;
+}
+
+char *extract_programmer_param(const char *param_name)
+{
+       return extract_param(&programmer_param, param_name, ",");
+}
+
+/* Returns the number of well-defined erasers for a chip. */
+static unsigned int count_usable_erasers(const struct flashctx *flash)
+{
+       unsigned int usable_erasefunctions = 0;
+       int k;
+       for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
+               if (!check_block_eraser(flash, k, 0))
+                       usable_erasefunctions++;
+       }
+       return usable_erasefunctions;
+}
+
+/* start is an offset to the base address of the flash chip */
+int check_erased_range(struct flashctx *flash, unsigned int start,
+                      unsigned int len)
+{
+       int ret;
+       uint8_t *cmpbuf = malloc(len);
+
+       if (!cmpbuf) {
+               msg_gerr("Could not allocate memory!\n");
+               exit(1);
+       }
+       memset(cmpbuf, 0xff, len);
+       ret = verify_range(flash, cmpbuf, start, len, "ERASE");
+       free(cmpbuf);
+       return ret;
+}
+
+/*
+ * @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
+ * @return     0 for success, -1 for failure
+ */
+int verify_range(struct flashctx *flash, uint8_t *cmpbuf, unsigned int start,
+                unsigned int len, const char *message)
+{
+       unsigned int i;
+       uint8_t *readbuf = malloc(len);
+       int ret = 0, failcount = 0;
+
+       if (!len)
+               goto out_free;
+
+       if (!flash->read) {
+               msg_cerr("ERROR: flashrom has no read function for this flash chip.\n");
+               return 1;
+       }
+       if (!readbuf) {
+               msg_gerr("Could not allocate memory!\n");
+               exit(1);
+       }
+
+       if (start + len > flash->total_size * 1024) {
+               msg_gerr("Error: %s called with start 0x%x + len 0x%x >"
+                       " total_size 0x%x\n", __func__, start, len,
+                       flash->total_size * 1024);
+               ret = -1;
+               goto out_free;
+       }
+       if (!message)
+               message = "VERIFY";
+
+       ret = flash->read(flash, readbuf, start, len);
+       if (ret) {
+               msg_gerr("Verification impossible because read failed "
+                        "at 0x%x (len 0x%x)\n", start, len);
+               return ret;
+       }
+
+       for (i = 0; i < len; i++) {
+               if (cmpbuf[i] != readbuf[i]) {
+                       /* Only print the first failure. */
+                       if (!failcount++)
+                               msg_cerr("%s FAILED at 0x%08x! "
+                                        "Expected=0x%02x, Read=0x%02x,",
+                                        message, start + i, cmpbuf[i],
+                                        readbuf[i]);
+               }
+       }
+       if (failcount) {
+               msg_cerr(" failed byte count from 0x%08x-0x%08x: 0x%x\n",
+                        start, start + len - 1, failcount);
+               ret = -1;
+       }
+
+out_free:
+       free(readbuf);
+       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.
+ * Warning: This function assumes that @have and @want point to naturally
+ * aligned regions.
+ *
+ * @have        buffer with current content
+ * @want        buffer with desired content
+ * @len                length of the checked 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, unsigned int len, enum write_granularity gran)
+{
+       int result = 0;
+       unsigned 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[j * 256 + i] != 0xff) {
+                                       result = 1;
+                                       break;
+                               }
+                       if (result)
+                               break;
+               }
+               break;
+       default:
+               msg_cerr("%s: Unsupported granularity! Please report a bug at "
+                        "flashrom@flashrom.org\n", __func__);
+       }
+       return result;
+}
+
+/**
+ * Check if the buffer @have needs to be programmed to get the content of @want.
+ * If yes, return 1 and fill in first_start with the start address of the
+ * write operation and first_len with the length of the first to-be-written
+ * chunk. If not, return 0 and leave first_start and first_len undefined.
+ *
+ * Warning: This function assumes that @have and @want point to naturally
+ * aligned regions.
+ *
+ * @have       buffer with current content
+ * @want       buffer with desired content
+ * @len                length of the checked area
+ * @gran       write granularity (enum, not count)
+ * @first_start        offset of the first byte which needs to be written (passed in
+ *             value is increased by the offset of the first needed write
+ *             relative to have/want or unchanged if no write is needed)
+ * @return     length of the first contiguous area which needs to be written
+ *             0 if no write is needed
+ *
+ * FIXME: This function needs a parameter which tells it about coalescing
+ * in relation to the max write length of the programmer and the max write
+ * length of the chip.
+ */
+static unsigned int get_next_write(uint8_t *have, uint8_t *want, unsigned int len,
+                         unsigned int *first_start,
+                         enum write_granularity gran)
+{
+       int need_write = 0;
+       unsigned int rel_start = 0, first_len = 0;
+       unsigned int i, limit, stride;
+
+       switch (gran) {
+       case write_gran_1bit:
+       case write_gran_1byte:
+               stride = 1;
+               break;
+       case write_gran_256bytes:
+               stride = 256;
+               break;
+       default:
+               msg_cerr("%s: Unsupported granularity! Please report a bug at "
+                        "flashrom@flashrom.org\n", __func__);
+               /* Claim that no write was needed. A write with unknown
+                * granularity is too dangerous to try.
+                */
+               return 0;
+       }
+       for (i = 0; i < len / stride; i++) {
+               limit = min(stride, len - i * stride);
+               /* Are 'have' and 'want' identical? */
+               if (memcmp(have + i * stride, want + i * stride, limit)) {
+                       if (!need_write) {
+                               /* First location where have and want differ. */
+                               need_write = 1;
+                               rel_start = i * stride;
+                       }
+               } else {
+                       if (need_write) {
+                               /* First location where have and want
+                                * do not differ anymore.
+                                */
+                               break;
+                       }
+               }
+       }
+       if (need_write)
+               first_len = min(i * stride - rel_start, len);
+       *first_start += rel_start;
+       return first_len;
+}
+
+/* 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) {
+               msg_gerr("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 & BUS_PARALLEL) && (max_rom_decode.parallel < size)) {
+               limitexceeded++;
+               msg_pdbg("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 & BUS_LPC) && (max_rom_decode.lpc < size)) {
+               limitexceeded++;
+               msg_pdbg("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 & BUS_FWH) && (max_rom_decode.fwh < size)) {
+               limitexceeded++;
+               msg_pdbg("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 & BUS_SPI) && (max_rom_decode.spi < size)) {
+               limitexceeded++;
+               msg_pdbg("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. */
+               msg_pdbg("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;
+}
+
+int probe_flash(struct registered_programmer *pgm, int startchip,
+               struct flashctx *fill_flash, int force)
+{
+       const struct flashchip *flash;
+       unsigned long base = 0;
+       char location[64];
+       uint32_t size;
+       enum chipbustype buses_common;
+       char *tmp;
+
+       for (flash = flashchips + startchip; flash && flash->name; flash++) {
+               if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
+                       continue;
+               buses_common = pgm->buses_supported & flash->bustype;
+               if (!buses_common)
+                       continue;
+               msg_gdbg("Probing for %s %s, %d kB: ",
+                            flash->vendor, flash->name, flash->total_size);
+               if (!flash->probe && !force) {
+                       msg_gdbg("failed! flashrom has no probe function for "
+                                "this flash chip.\n");
+                       continue;
+               }
+
+               size = flash->total_size * 1024;
+               check_max_decode(buses_common, size);
+
+               /* Start filling in the dynamic data. */
+               memcpy(fill_flash, flash, sizeof(struct flashchip));
+               fill_flash->pgm = pgm;
+
+               base = flashbase ? flashbase : (0xffffffff - size + 1);
+               fill_flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
+
+               if (force)
+                       break;
+
+               if (fill_flash->probe(fill_flash) != 1)
+                       goto notfound;
+
+               /* If this is the first chip found, accept it.
+                * If this is not the first chip found, accept it only if it is
+                * a non-generic match. SFDP and CFI are generic matches.
+                * startchip==0 means this call to probe_flash() is the first
+                * one for this programmer interface and thus no other chip has
+                * been found on this interface.
+                */
+               if (startchip == 0 && fill_flash->model_id == SFDP_DEVICE_ID) {
+                       msg_cinfo("===\n"
+                                 "SFDP has autodetected a flash chip which is "
+                                 "not natively supported by flashrom yet.\n");
+                       if (count_usable_erasers(fill_flash) == 0)
+                               msg_cinfo("The standard operations read and "
+                                         "verify should work, but to support "
+                                         "erase, write and all other "
+                                         "possible features");
+                       else
+                               msg_cinfo("All standard operations (read, "
+                                         "verify, erase and write) should "
+                                         "work, but to support all possible "
+                                         "features");
+
+                       msg_cinfo(" we need to add them manually.\nYou "
+                                 "can help us by mailing us the output of "
+                                 "the following command to flashrom@flashrom."
+                                 "org: \n'flashrom -VV [plus the "
+                                 "-p/--programmer parameter (if needed)]"
+                                 "'\nThanks for your help!\n"
+                                 "===\n");
+               }
+
+               if (startchip == 0 ||
+                   ((fill_flash->model_id != GENERIC_DEVICE_ID) &&
+                    (fill_flash->model_id != SFDP_DEVICE_ID)))
+                       break;
+
+notfound:
+               programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
+       }
+
+       if (!flash || !flash->name)
+               return -1;
+
+#if CONFIG_INTERNAL == 1
+       if (programmer_table[programmer].map_flash_region == physmap)
+               snprintf(location, sizeof(location), "at physical address 0x%lx", base);
+       else
+#endif
+               snprintf(location, sizeof(location), "on %s", programmer_table[programmer].name);
+
+       tmp = flashbuses_to_text(flash->bustype);
+       msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) %s.\n",
+                 force ? "Assuming" : "Found", fill_flash->vendor,
+                 fill_flash->name, fill_flash->total_size, tmp, location);
+       free(tmp);
+
+       /* Flash registers will not be mapped if the chip was forced. Lock info
+        * may be stored in registers, so avoid lock info printing.
+        */
+       if (!force)
+               if (fill_flash->printlock)
+                       fill_flash->printlock(fill_flash);
+
+       /* Return position of matching chip. */
+       return flash - flashchips;
+}
+
+int verify_flash(struct flashctx *flash, uint8_t *buf)
+{
+       int ret;
+       unsigned int total_size = flash->total_size * 1024;
+
+       msg_cinfo("Verifying flash... ");
+
+       ret = verify_range(flash, buf, 0, total_size, NULL);
+
+       if (!ret)
+               msg_cinfo("VERIFIED.          \n");
+
+       return ret;
+}
+
+int read_buf_from_file(unsigned char *buf, unsigned long size,
+                      const char *filename)
+{
+       unsigned long numbytes;
+       FILE *image;
+       struct stat image_stat;
+
+       if ((image = fopen(filename, "rb")) == NULL) {
+               perror(filename);
+               return 1;
+       }
+       if (fstat(fileno(image), &image_stat) != 0) {
+               perror(filename);
+               fclose(image);
+               return 1;
+       }
+       if (image_stat.st_size != size) {
+               msg_gerr("Error: Image size doesn't match\n");
+               fclose(image);
+               return 1;
+       }
+       numbytes = fread(buf, 1, size, image);
+       if (fclose(image)) {
+               perror(filename);
+               return 1;
+       }
+       if (numbytes != size) {
+               msg_gerr("Error: Failed to read complete file. Got %ld bytes, "
+                        "wanted %ld!\n", numbytes, size);
+               return 1;
+       }
+       return 0;
+}
+
+int write_buf_to_file(unsigned char *buf, unsigned long size,
+                     const char *filename)
+{
+       unsigned long numbytes;
+       FILE *image;
+
+       if (!filename) {
+               msg_gerr("No filename specified.\n");
+               return 1;
+       }
+       if ((image = fopen(filename, "wb")) == NULL) {
+               perror(filename);
+               return 1;
+       }
+
+       numbytes = fwrite(buf, 1, size, image);
+       fclose(image);
+       if (numbytes != size) {
+               msg_gerr("File %s could not be written completely.\n",
+                        filename);
+               return 1;
+       }
+       return 0;
+}
+
+int read_flash_to_file(struct flashctx *flash, const char *filename)
+{
+       unsigned long size = flash->total_size * 1024;
+       unsigned char *buf = calloc(size, sizeof(char));
+       int ret = 0;
+
+       msg_cinfo("Reading flash... ");
+       if (!buf) {
+               msg_gerr("Memory allocation failed!\n");
+               msg_cinfo("FAILED.\n");
+               return 1;
+       }
+       if (!flash->read) {
+               msg_cerr("No read function available for this flash chip.\n");
+               ret = 1;
+               goto out_free;
+       }
+       if (flash->read(flash, buf, 0, size)) {
+               msg_cerr("Read operation failed!\n");
+               ret = 1;
+               goto out_free;
+       }
+
+       ret = write_buf_to_file(buf, size, filename);
+out_free:
+       free(buf);
+       msg_cinfo("%s.\n", ret ? "FAILED" : "done");
+       return ret;
+}
+
+/* This function shares a lot of its structure with erase_and_write_flash() and
+ * walk_eraseregions().
+ * Even if an error is found, the function will keep going and check the rest.
+ */
+static int selfcheck_eraseblocks(const 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_gspew("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;
+}
+
+static int erase_and_write_block_helper(struct flashctx *flash,
+                                       unsigned int start, unsigned int len,
+                                       uint8_t *curcontents,
+                                       uint8_t *newcontents,
+                                       int (*erasefn) (struct flashctx *flash,
+                                                       unsigned int addr,
+                                                       unsigned int len))
+{
+       unsigned int starthere = 0, lenhere = 0;
+       int ret = 0, skip = 1, writecount = 0;
+       enum write_granularity gran = write_gran_256bytes; /* FIXME */
+
+       /* curcontents and newcontents are opaque to walk_eraseregions, and
+        * need to be adjusted here to keep the impression of proper abstraction
+        */
+       curcontents += start;
+       newcontents += start;
+       msg_cdbg(":");
+       /* FIXME: Assume 256 byte granularity for now to play it safe. */
+       if (need_erase(curcontents, newcontents, len, gran)) {
+               msg_cdbg("E");
+               ret = erasefn(flash, start, len);
+               if (ret)
+                       return ret;
+               if (check_erased_range(flash, start, len)) {
+                       msg_cerr("ERASE FAILED!\n");
+                       return -1;
+               }
+               /* Erase was successful. Adjust curcontents. */
+               memset(curcontents, 0xff, len);
+               skip = 0;
+       }
+       /* get_next_write() sets starthere to a new value after the call. */
+       while ((lenhere = get_next_write(curcontents + starthere,
+                                        newcontents + starthere,
+                                        len - starthere, &starthere, gran))) {
+               if (!writecount++)
+                       msg_cdbg("W");
+               /* Needs the partial write function signature. */
+               ret = flash->write(flash, newcontents + starthere,
+                                  start + starthere, lenhere);
+               if (ret)
+                       return ret;
+               starthere += lenhere;
+               skip = 0;
+       }
+       if (skip)
+               msg_cdbg("S");
+       return ret;
+}
+
+static int walk_eraseregions(struct flashctx *flash, int erasefunction,
+                            int (*do_something) (struct flashctx *flash,
+                                                 unsigned int addr,
+                                                 unsigned int len,
+                                                 uint8_t *param1,
+                                                 uint8_t *param2,
+                                                 int (*erasefn) (
+                                                       struct flashctx *flash,
+                                                       unsigned int addr,
+                                                       unsigned int len)),
+                            void *param1, void *param2)
+{
+       int i, j;
+       unsigned int start = 0;
+       unsigned int len;
+       struct block_eraser eraser = flash->block_erasers[erasefunction];
+
+       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.
+                */
+               len = eraser.eraseblocks[i].size;
+               for (j = 0; j < eraser.eraseblocks[i].count; j++) {
+                       /* Print this for every block except the first one. */
+                       if (i || j)
+                               msg_cdbg(", ");
+                       msg_cdbg("0x%06x-0x%06x", start,
+                                    start + len - 1);
+                       if (do_something(flash, start, len, param1, param2,
+                                        eraser.block_erase)) {
+                               return 1;
+                       }
+                       start += len;
+               }
+       }
+       msg_cdbg("\n");
+       return 0;
+}
+
+static int check_block_eraser(const struct flashctx *flash, int k, int log)
+{
+       struct block_eraser eraser = flash->block_erasers[k];
+
+       if (!eraser.block_erase && !eraser.eraseblocks[0].count) {
+               if (log)
+                       msg_cdbg("not defined. ");
+               return 1;
+       }
+       if (!eraser.block_erase && eraser.eraseblocks[0].count) {
+               if (log)
+                       msg_cdbg("eraseblock layout is known, but matching "
+                                "block erase function is not implemented. ");
+               return 1;
+       }
+       if (eraser.block_erase && !eraser.eraseblocks[0].count) {
+               if (log)
+                       msg_cdbg("block erase function found, but "
+                                "eraseblock layout is not defined. ");
+               return 1;
+       }
+       return 0;
+}
+
+int erase_and_write_flash(struct flashctx *flash, uint8_t *oldcontents,
+                         uint8_t *newcontents)
+{
+       int k, ret = 1;
+       uint8_t *curcontents;
+       unsigned long size = flash->total_size * 1024;
+       unsigned int usable_erasefunctions = count_usable_erasers(flash);
+
+       msg_cinfo("Erasing and writing flash chip... ");
+       curcontents = malloc(size);
+       if (!curcontents) {
+               msg_gerr("Out of memory!\n");
+               exit(1);
+       }
+       /* Copy oldcontents to curcontents to avoid clobbering oldcontents. */
+       memcpy(curcontents, oldcontents, size);
+
+       for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
+               if (k != 0)
+                       msg_cdbg("Looking for another erase function.\n");
+               if (!usable_erasefunctions) {
+                       msg_cdbg("No usable erase functions left.\n");
+                       break;
+               }
+               msg_cdbg("Trying erase function %i... ", k);
+               if (check_block_eraser(flash, k, 1))
+                       continue;
+               usable_erasefunctions--;
+               ret = walk_eraseregions(flash, k, &erase_and_write_block_helper,
+                                       curcontents, newcontents);
+               /* If everything is OK, don't try another erase function. */
+               if (!ret)
+                       break;
+               /* Write/erase failed, so try to find out what the current chip
+                * contents are. If no usable erase functions remain, we can
+                * skip this: the next iteration will break immediately anyway.
+                */
+               if (!usable_erasefunctions)
+                       continue;
+               /* Reading the whole chip may take a while, inform the user even
+                * in non-verbose mode.
+                */
+               msg_cinfo("Reading current flash chip contents... ");
+               if (flash->read(flash, curcontents, 0, size)) {
+                       /* Now we are truly screwed. Read failed as well. */
+                       msg_cerr("Can't read anymore! Aborting.\n");
+                       /* We have no idea about the flash chip contents, so
+                        * retrying with another erase function is pointless.
+                        */
+                       break;
+               }
+               msg_cinfo("done. ");
+       }
+       /* Free the scratchpad. */
+       free(curcontents);
+
+       if (ret) {
+               msg_cerr("FAILED!\n");
+       } else {
+               msg_cinfo("Erase/write done.\n");
+       }
+       return ret;
+}
+
+void nonfatal_help_message(void)
+{
+       msg_gerr("Writing to the flash chip apparently didn't do anything.\n"
+               "This means we have to add special support for your board, "
+                 "programmer or flash chip.\n"
+               "Please report this on IRC at irc.freenode.net (channel "
+                 "#flashrom) or\n"
+               "mail flashrom@flashrom.org!\n"
+               "-------------------------------------------------------------"
+                 "------------------\n"
+               "You may now reboot or simply leave the machine running.\n");
+}
+
+void emergency_help_message(void)
+{
+       msg_gerr("Your flash chip is in an unknown state.\n"
+               "Get help on IRC at chat.freenode.net (channel #flashrom) or\n"
+               "mail flashrom@flashrom.org with the subject "
+               "\"FAILED: <your board name>\"!\n"
+               "-------------------------------------------------------------"
+                 "------------------\n"
+               "DO NOT REBOOT OR POWEROFF!\n");
+}
+
+/* The way to go if you want a delimited list of programmers */
+void list_programmers(const char *delim)
+{
+       enum programmer p;
+       for (p = 0; p < PROGRAMMER_INVALID; p++) {
+               msg_ginfo("%s", programmer_table[p].name);
+               if (p < PROGRAMMER_INVALID - 1)
+                       msg_ginfo("%s", delim);
+       }
+       msg_ginfo("\n");        
+}
+
+void list_programmers_linebreak(int startcol, int cols, int paren)
+{
+       const char *pname;
+       int pnamelen;
+       int remaining = 0, firstline = 1;
+       enum programmer p;
+       int i;
+
+       for (p = 0; p < PROGRAMMER_INVALID; p++) {
+               pname = programmer_table[p].name;
+               pnamelen = strlen(pname);
+               if (remaining - pnamelen - 2 < 0) {
+                       if (firstline)
+                               firstline = 0;
+                       else
+                               msg_ginfo("\n");
+                       for (i = 0; i < startcol; i++)
+                               msg_ginfo(" ");
+                       remaining = cols - startcol;
+               } else {
+                       msg_ginfo(" ");
+                       remaining--;
+               }
+               if (paren && (p == 0)) {
+                       msg_ginfo("(");
+                       remaining--;
+               }
+               msg_ginfo("%s", pname);
+               remaining -= pnamelen;
+               if (p < PROGRAMMER_INVALID - 1) {
+                       msg_ginfo(",");
+                       remaining--;
+               } else {
+                       if (paren)
+                               msg_ginfo(")");
+                       msg_ginfo("\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
+}
+
+void print_buildinfo(void)
+{
+       msg_gdbg("flashrom was built with");
+#if NEED_PCI == 1
+#ifdef PCILIB_VERSION
+       msg_gdbg(" libpci %s,", PCILIB_VERSION);
+#else
+       msg_gdbg(" unknown PCI library,");
+#endif
+#endif
+#ifdef __clang__
+       msg_gdbg(" LLVM Clang");
+#ifdef __clang_version__
+       msg_gdbg(" %s,", __clang_version__);
+#else
+       msg_gdbg(" unknown version (before r102686),");
+#endif
+#elif defined(__GNUC__)
+       msg_gdbg(" GCC");
+#ifdef __VERSION__
+       msg_gdbg(" %s,", __VERSION__);
+#else
+       msg_gdbg(" unknown version,");
+#endif
+#else
+       msg_gdbg(" unknown compiler,");
+#endif
+#if defined (__FLASHROM_LITTLE_ENDIAN__)
+       msg_gdbg(" little endian");
+#elif defined (__FLASHROM_BIG_ENDIAN__)
+       msg_gdbg(" big endian");
+#else
+#error Endianness could not be determined
+#endif
+       msg_gdbg("\n");
+}
+
+void print_version(void)
+{
+       msg_ginfo("flashrom v%s", flashrom_version);
+       print_sysinfo();
+       msg_ginfo("\n");
+}
+
+void print_banner(void)
+{
+       msg_ginfo("flashrom is free software, get the source code at "
+                 "http://www.flashrom.org\n");
+       msg_ginfo("\n");
+}
+
+int selfcheck(void)
+{
+       int ret = 0;
+       const struct flashchip *flash;
+
+       /* Safety check. Instead of aborting after the first error, check
+        * if more errors exist.
+        */
+       if (ARRAY_SIZE(programmer_table) - 1 != PROGRAMMER_INVALID) {
+               msg_gerr("Programmer table miscompilation!\n");
+               ret = 1;
+       }
+       /* It would be favorable if we could also check for correct termination
+        * of the following arrays, but we don't know their sizes in here...
+        * For 'flashchips' we check the first element to be non-null. In the
+        * other cases there exist use cases where the first element can be
+        * null. */
+       if (flashchips == NULL || flashchips[0].vendor == NULL) {
+               msg_gerr("Flashchips table miscompilation!\n");
+               ret = 1;
+       }
+       /* Check that virtual_memory in struct flashctx is placed directly
+        * after the members copied from struct flashchip.
+        */
+       if (sizeof(struct flashchip) !=
+           offsetof(struct flashctx, virtual_memory)) {
+               msg_gerr("struct flashctx broken!\n");
+               ret = 1;
+       }
+       for (flash = flashchips; flash && flash->name; flash++)
+               if (selfcheck_eraseblocks(flash))
+                       ret = 1;
+
+#if CONFIG_INTERNAL == 1
+       if (chipset_enables == NULL) {
+               msg_gerr("Chipset enables table does not exist!\n");
+               ret = 1;
+       }
+       if (board_matches == NULL) {
+               msg_gerr("Board enables table does not exist!\n");
+               ret = 1;
+       }
+       if (boards_known == NULL) {
+               msg_gerr("Known boards table does not exist!\n");
+               ret = 1;
+       }
+       if (laptops_known == NULL) {
+               msg_gerr("Known laptops table does not exist!\n");
+               ret = 1;
+       }
+#endif
+       return ret;
+}
+
+void check_chip_supported(const struct flashctx *flash)
+{
+       if (flash->feature_bits & FEATURE_OTP) {
+               msg_cdbg("This chip may contain one-time programmable memory. "
+                        "flashrom cannot read\nand may never be able to write "
+                        "it, hence it may not be able to completely\n"
+                        "clone the contents of this chip (see man page for "
+                        "details).\n");
+       }
+       if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) {
+               msg_cinfo("===\n");
+               if (flash->tested & TEST_BAD_MASK) {
+                       msg_cinfo("This flash part has status NOT WORKING for operations:");
+                       if (flash->tested & TEST_BAD_PROBE)
+                               msg_cinfo(" PROBE");
+                       if (flash->tested & TEST_BAD_READ)
+                               msg_cinfo(" READ");
+                       if (flash->tested & TEST_BAD_ERASE)
+                               msg_cinfo(" ERASE");
+                       if (flash->tested & TEST_BAD_WRITE)
+                               msg_cinfo(" WRITE");
+                       msg_cinfo("\n");
+               }
+               if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) ||
+                   (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) ||
+                   (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) ||
+                   (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) {
+                       msg_cinfo("This flash part has status UNTESTED for operations:");
+                       if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
+                               msg_cinfo(" PROBE");
+                       if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
+                               msg_cinfo(" READ");
+                       if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
+                               msg_cinfo(" ERASE");
+                       if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
+                               msg_cinfo(" WRITE");
+                       msg_cinfo("\n");
+               }
+               /* FIXME: This message is designed towards CLI users. */
+               msg_cinfo("The test status of this chip may have been updated "
+                           "in the latest development\n"
+                         "version of flashrom. If you are running the latest "
+                           "development version,\n"
+                         "please email a report to flashrom@flashrom.org if "
+                           "any of the above operations\n"
+                         "work correctly for you with this flash part. Please "
+                           "include the flashrom\n"
+                         "output with the additional -V option for all "
+                           "operations you tested (-V, -Vr,\n"
+                         "-VE, -Vw), and mention which mainboard or "
+                           "programmer you tested.\n"
+                         "Please mention your board in the subject line. "
+                           "Thanks for your help!\n");
+       }
+}
+
+/* FIXME: This function signature needs to be improved once doit() has a better
+ * function signature.
+ */
+int chip_safety_check(struct flashctx *flash, int force, int read_it,
+                     int write_it, int erase_it, int verify_it)
+{
+       if (!programmer_may_write && (write_it || erase_it)) {
+               msg_perr("Write/erase is not working yet on your programmer in "
+                        "its current configuration.\n");
+               /* --force is the wrong approach, but it's the best we can do
+                * until the generic programmer parameter parser is merged.
+                */
+               if (!force)
+                       return 1;
+               msg_cerr("Continuing anyway.\n");
+       }
+
+       if (read_it || erase_it || write_it || verify_it) {
+               /* Everything needs read. */
+               if (flash->tested & TEST_BAD_READ) {
+                       msg_cerr("Read is not working on this chip. ");
+                       if (!force)
+                               return 1;
+                       msg_cerr("Continuing anyway.\n");
+               }
+               if (!flash->read) {
+                       msg_cerr("flashrom has no read function for this "
+                                "flash chip.\n");
+                       return 1;
+               }
+       }
+       if (erase_it || write_it) {
+               /* Write needs erase. */
+               if (flash->tested & TEST_BAD_ERASE) {
+                       msg_cerr("Erase is not working on this chip. ");
+                       if (!force)
+                               return 1;
+                       msg_cerr("Continuing anyway.\n");
+               }
+               if(count_usable_erasers(flash) == 0) {
+                       msg_cerr("flashrom has no erase function for this "
+                                "flash chip.\n");
+                       return 1;
+               }
+       }
+       if (write_it) {
+               if (flash->tested & TEST_BAD_WRITE) {
+                       msg_cerr("Write is not working on this chip. ");
+                       if (!force)
+                               return 1;
+                       msg_cerr("Continuing anyway.\n");
+               }
+               if (!flash->write) {
+                       msg_cerr("flashrom has no write function for this "
+                                "flash chip.\n");
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* This function signature is horrible. We need to design a better interface,
+ * but right now it allows us to split off the CLI code.
+ * Besides that, the function itself is a textbook example of abysmal code flow.
+ */
+int doit(struct flashctx *flash, int force, const char *filename, int read_it,
+        int write_it, int erase_it, int verify_it)
+{
+       uint8_t *oldcontents;
+       uint8_t *newcontents;
+       int ret = 0;
+       unsigned long size = flash->total_size * 1024;
+
+       if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) {
+               msg_cerr("Aborting.\n");
+               ret = 1;
+               goto out_nofree;
+       }
+
+       /* Given the existence of read locks, we want to unlock for read,
+        * erase and write.
+        */
+       if (flash->unlock)
+               flash->unlock(flash);
+
+       if (read_it) {
+               ret = read_flash_to_file(flash, filename);
+               goto out_nofree;
+       }
+
+       oldcontents = malloc(size);
+       if (!oldcontents) {
+               msg_gerr("Out of memory!\n");
+               exit(1);
+       }
+       /* Assume worst case: All bits are 0. */
+       memset(oldcontents, 0x00, size);
+       newcontents = malloc(size);
+       if (!newcontents) {
+               msg_gerr("Out of memory!\n");
+               exit(1);
+       }
+       /* Assume best case: All bits should be 1. */
+       memset(newcontents, 0xff, size);
+       /* Side effect of the assumptions above: Default write action is erase
+        * because newcontents looks like a completely erased chip, and
+        * oldcontents being completely 0x00 means we have to erase everything
+        * before we can write.
+        */
+
+       if (erase_it) {
+               /* FIXME: Do we really want the scary warning if erase failed?
+                * After all, after erase the chip is either blank or partially
+                * blank or it has the old contents. A blank chip won't boot,
+                * so if the user wanted erase and reboots afterwards, the user
+                * knows very well that booting won't work.
+                */
+               if (erase_and_write_flash(flash, oldcontents, newcontents)) {
+                       emergency_help_message();
+                       ret = 1;
+               }
+               goto out;
+       }
+
+       if (write_it || verify_it) {
+               if (read_buf_from_file(newcontents, size, filename)) {
+                       ret = 1;
+                       goto out;
+               }
+
+#if CONFIG_INTERNAL == 1
+               if (programmer == PROGRAMMER_INTERNAL)
+                       if (show_id(newcontents, size, force)) {
+                               ret = 1;
+                               goto out;
+                       }
+#endif
+       }
+
+       /* Read the whole chip to be able to check whether regions need to be
+        * erased and to give better diagnostics in case write fails.
+        * The alternative would be to read only the regions which are to be
+        * preserved, but in that case we might perform unneeded erase which
+        * takes time as well.
+        */
+       msg_cinfo("Reading old flash chip contents... ");
+       if (flash->read(flash, oldcontents, 0, size)) {
+               ret = 1;
+               msg_cinfo("FAILED.\n");
+               goto out;
+       }
+       msg_cinfo("done.\n");
+
+       // This should be moved into each flash part's code to do it 
+       // cleanly. This does the job.
+       handle_romentries(flash, oldcontents, newcontents);
+
+       // ////////////////////////////////////////////////////////////
+
+       if (write_it) {
+               if (erase_and_write_flash(flash, oldcontents, newcontents)) {
+                       msg_cerr("Uh oh. Erase/write failed. Checking if "
+                                "anything changed.\n");
+                       if (!flash->read(flash, newcontents, 0, size)) {
+                               if (!memcmp(oldcontents, newcontents, size)) {
+                                       msg_cinfo("Good. It seems nothing was "
+                                                 "changed.\n");
+                                       nonfatal_help_message();
+                                       ret = 1;
+                                       goto out;
+                               }
+                       }
+                       emergency_help_message();
+                       ret = 1;
+                       goto out;
+               }
+       }
+
+       if (verify_it) {
+               /* Work around chips which need some time to calm down. */
+               if (write_it)
+                       programmer_delay(1000*1000);
+               ret = verify_flash(flash, newcontents);
+               /* If we tried to write, and verification now fails, we
+                * might have an emergency situation.
+                */
+               if (ret && write_it)
+                       emergency_help_message();
+       }
+
+out:
+       free(oldcontents);
+       free(newcontents);
+out_nofree:
+       programmer_shutdown();
+       return ret;
+}
diff --git a/ft2232_spi.c b/ft2232_spi.c
new file mode 100644 (file)
index 0000000..a5d3828
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
+ * 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; 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
+ */
+
+#if CONFIG_FT2232_SPI == 1
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "flash.h"
+#include "programmer.h"
+#include "spi.h"
+#include <ftdi.h>
+
+/* Please keep sorted by vendor ID, then device ID. */
+
+#define FTDI_VID               0x0403
+#define FTDI_FT2232H_PID       0x6010
+#define FTDI_FT4232H_PID       0x6011
+#define TIAO_TUMPA_PID         0x8a98
+#define AMONTEC_JTAGKEY_PID    0xCFF8
+
+#define GOEPEL_VID             0x096C
+#define GOEPEL_PICOTAP_PID     0x1449
+
+#define FIC_VID                        0x1457
+#define OPENMOKO_DBGBOARD_PID  0x5118
+
+#define OLIMEX_VID             0x15BA
+#define OLIMEX_ARM_OCD_PID     0x0003
+#define OLIMEX_ARM_TINY_PID    0x0004
+#define OLIMEX_ARM_OCD_H_PID   0x002B
+#define OLIMEX_ARM_TINY_H_PID  0x002A
+
+const struct usbdev_status devs_ft2232spi[] = {
+       {FTDI_VID, FTDI_FT2232H_PID, OK, "FTDI", "FT2232H"},
+       {FTDI_VID, FTDI_FT4232H_PID, OK, "FTDI", "FT4232H"},
+       {FTDI_VID, TIAO_TUMPA_PID, OK, "TIAO", "USB Multi-Protocol Adapter"},
+       {FTDI_VID, AMONTEC_JTAGKEY_PID, OK, "Amontec", "JTAGkey"},
+       {GOEPEL_VID, GOEPEL_PICOTAP_PID, OK, "GOEPEL", "PicoTAP"},
+       {FIC_VID, OPENMOKO_DBGBOARD_PID, OK, "FIC",
+               "OpenMoko Neo1973 Debug board (V2+)"},
+       {OLIMEX_VID, OLIMEX_ARM_OCD_PID, NT, "Olimex", "ARM-USB-OCD"},
+       {OLIMEX_VID, OLIMEX_ARM_TINY_PID, OK, "Olimex", "ARM-USB-TINY"},
+       {OLIMEX_VID, OLIMEX_ARM_OCD_H_PID, NT, "Olimex", "ARM-USB-OCD-H"},
+       {OLIMEX_VID, OLIMEX_ARM_TINY_H_PID, NT, "Olimex", "ARM-USB-TINY-H"},
+       {},
+};
+
+
+#define DEFAULT_DIVISOR 2
+
+#define BITMODE_BITBANG_NORMAL 1
+#define BITMODE_BITBANG_SPI    2
+
+/* 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
+ *
+ * JTAGkey(2) needs to enable its output via Bit4 / GPIOL0
+ *  value: 0x18  OE=high, CS=high, DI=low, DO=low, SK=low
+ *    dir: 0x1b  OE=output, CS=output, DI=input, DO=output, SK=output
+ */
+static uint8_t cs_bits = 0x08;
+static uint8_t pindir = 0x0b;
+static struct ftdi_context ftdic_context;
+
+static const char *get_ft2232_devicename(int ft2232_vid, int ft2232_type)
+{
+       int i;
+       for (i = 0; devs_ft2232spi[i].vendor_name != NULL; i++) {
+               if ((devs_ft2232spi[i].device_id == ft2232_type)
+                       && (devs_ft2232spi[i].vendor_id == ft2232_vid))
+                               return devs_ft2232spi[i].device_name;
+       }
+       return "unknown device";
+}
+
+static const char *get_ft2232_vendorname(int ft2232_vid, int ft2232_type)
+{
+       int i;
+       for (i = 0; devs_ft2232spi[i].vendor_name != NULL; i++) {
+               if ((devs_ft2232spi[i].device_id == ft2232_type)
+                       && (devs_ft2232spi[i].vendor_id == ft2232_vid))
+                               return devs_ft2232spi[i].vendor_name;
+       }
+       return "unknown vendor";
+}
+
+static 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) {
+               msg_perr("ftdi_write_data: %d, %s\n", r,
+                               ftdi_get_error_string(ftdic));
+               return 1;
+       }
+       return 0;
+}
+
+static int get_buf(struct ftdi_context *ftdic, const unsigned char *buf,
+                  int size)
+{
+       int r;
+
+       while (size > 0) {
+               r = ftdi_read_data(ftdic, (unsigned char *) buf, size);
+               if (r < 0) {
+                       msg_perr("ftdi_read_data: %d, %s\n", r,
+                                       ftdi_get_error_string(ftdic));
+                       return 1;
+               }
+               buf += r;
+               size -= r;
+       }
+       return 0;
+}
+
+static int ft2232_spi_send_command(struct flashctx *flash,
+                                  unsigned int writecnt, unsigned int readcnt,
+                                  const unsigned char *writearr,
+                                  unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_ft2232 = {
+       .type           = SPI_CONTROLLER_FT2232,
+       .max_data_read  = 64 * 1024,
+       .max_data_write = 256,
+       .command        = ft2232_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = default_spi_read,
+       .write_256      = default_spi_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+/* Returns 0 upon success, a negative number upon errors. */
+int ft2232_spi_init(void)
+{
+       int ret = 0;
+       struct ftdi_context *ftdic = &ftdic_context;
+       unsigned char buf[512];
+       int ft2232_vid = FTDI_VID;
+       int ft2232_type = FTDI_FT4232H_PID;
+       enum ftdi_interface ft2232_interface = INTERFACE_B;
+       /*
+        * The 'H' chips can run with an internal clock of either 12 MHz or 60 MHz,
+        * but the non-H chips can only run at 12 MHz. We enable the divide-by-5
+        * prescaler on the former to run on the same speed.
+        */
+       uint8_t clock_5x = 1;
+       /* In addition to the prescaler mentioned above there is also another
+        * configurable one on all versions of the chips. Its divisor div can be
+        * set by a 16 bit value x according to the following formula:
+        * div = (1 + x) * 2 <-> x = div / 2 - 1
+        * Hence the expressible divisors are all even numbers between 2 and
+        * 2^17 (=131072) resulting in SCK frequencies of 6 MHz down to about
+        * 92 Hz for 12 MHz inputs.
+        */
+       uint32_t divisor = DEFAULT_DIVISOR;
+       int f;
+       char *arg;
+       double mpsse_clk;
+
+       arg = extract_programmer_param("type");
+       if (arg) {
+               if (!strcasecmp(arg, "2232H"))
+                       ft2232_type = FTDI_FT2232H_PID;
+               else if (!strcasecmp(arg, "4232H"))
+                       ft2232_type = FTDI_FT4232H_PID;
+               else if (!strcasecmp(arg, "jtagkey")) {
+                       ft2232_type = AMONTEC_JTAGKEY_PID;
+                       ft2232_interface = INTERFACE_A;
+                       cs_bits = 0x18;
+                       pindir = 0x1b;
+               } else if (!strcasecmp(arg, "picotap")) {
+                       ft2232_vid = GOEPEL_VID;
+                       ft2232_type = GOEPEL_PICOTAP_PID;
+                       ft2232_interface = INTERFACE_A;
+               } else if (!strcasecmp(arg, "tumpa")) {
+                       /* Interface A is SPI1, B is SPI2. */
+                       ft2232_type = TIAO_TUMPA_PID;
+                       ft2232_interface = INTERFACE_A;
+               } else if (!strcasecmp(arg, "busblaster")) {
+                       /* In its default configuration it is a jtagkey clone */
+                       ft2232_type = FTDI_FT2232H_PID;
+                       ft2232_interface = INTERFACE_A;
+                       cs_bits = 0x18;
+                       pindir = 0x1b;
+               } else if (!strcasecmp(arg, "openmoko")) {
+                       ft2232_vid = FIC_VID;
+                       ft2232_type = OPENMOKO_DBGBOARD_PID;
+                       ft2232_interface = INTERFACE_A;
+               } else if (!strcasecmp(arg, "arm-usb-ocd")) {
+                       ft2232_vid = OLIMEX_VID;
+                       ft2232_type = OLIMEX_ARM_OCD_PID;
+                       ft2232_interface = INTERFACE_A;
+                       cs_bits = 0x08;
+                       pindir = 0x1b;
+               } else if (!strcasecmp(arg, "arm-usb-tiny")) {
+                       ft2232_vid = OLIMEX_VID;
+                       ft2232_type = OLIMEX_ARM_TINY_PID;
+                       ft2232_interface = INTERFACE_A;
+               } else if (!strcasecmp(arg, "arm-usb-ocd-h")) {
+                       ft2232_vid = OLIMEX_VID;
+                       ft2232_type = OLIMEX_ARM_OCD_H_PID;
+                       ft2232_interface = INTERFACE_A;
+                       cs_bits = 0x08;
+                       pindir = 0x1b;
+               } else if (!strcasecmp(arg, "arm-usb-tiny-h")) {
+                       ft2232_vid = OLIMEX_VID;
+                       ft2232_type = OLIMEX_ARM_TINY_H_PID;
+                       ft2232_interface = INTERFACE_A;
+               } else {
+                       msg_perr("Error: Invalid device type specified.\n");
+                       free(arg);
+                       return -1;
+               }
+       }
+       free(arg);
+       arg = extract_programmer_param("port");
+       if (arg) {
+               switch (toupper((unsigned char)*arg)) {
+               case 'A':
+                       ft2232_interface = INTERFACE_A;
+                       break;
+               case 'B':
+                       ft2232_interface = INTERFACE_B;
+                       break;
+               default:
+                       msg_perr("Error: Invalid port/interface specified.\n");
+                       free(arg);
+                       return -2;
+               }
+       }
+       free(arg);
+       arg = extract_programmer_param("divisor");
+       if (arg && strlen(arg)) {
+               unsigned int temp = 0;
+               char *endptr;
+               temp = strtoul(arg, &endptr, 10);
+               if (*endptr || temp < 2 || temp > 131072 || temp & 0x1) {
+                       msg_perr("Error: Invalid SPI frequency divisor specified: \"%s\".\n"
+                                "Valid are even values between 2 and 131072.\n", arg);
+                       free(arg);
+                       return -2;
+               } else {
+                       divisor = (uint32_t)temp;
+               }
+       }
+       free(arg);
+       msg_pdbg("Using device type %s %s ",
+                get_ft2232_vendorname(ft2232_vid, ft2232_type),
+                get_ft2232_devicename(ft2232_vid, ft2232_type));
+       msg_pdbg("interface %s\n",
+                (ft2232_interface == INTERFACE_A) ? "A" : "B");
+
+       if (ftdi_init(ftdic) < 0) {
+               msg_perr("ftdi_init failed\n");
+               return -3;
+       }
+
+       f = ftdi_usb_open(ftdic, ft2232_vid, ft2232_type);
+
+       if (f < 0 && f != -5) {
+               msg_perr("Unable to open FTDI device: %d (%s)\n", f,
+                               ftdi_get_error_string(ftdic));
+               return -4;
+       }
+
+       if (ftdic->type != TYPE_2232H && ftdic->type != TYPE_4232H) {
+               msg_pdbg("FTDI chip type %d is not high-speed\n",
+                       ftdic->type);
+               clock_5x = 0;
+       }
+
+       if (ftdi_set_interface(ftdic, ft2232_interface) < 0) {
+               msg_perr("Unable to select interface: %s\n",
+                               ftdic->error_str);
+       }
+
+       if (ftdi_usb_reset(ftdic) < 0) {
+               msg_perr("Unable to reset FTDI device\n");
+       }
+
+       if (ftdi_set_latency_timer(ftdic, 2) < 0) {
+               msg_perr("Unable to set latency timer\n");
+       }
+
+       if (ftdi_write_data_set_chunksize(ftdic, 256)) {
+               msg_perr("Unable to set chunk size\n");
+       }
+
+       if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) {
+               msg_perr("Unable to set bitmode to SPI\n");
+       }
+
+       if (clock_5x) {
+               msg_pdbg("Disable divide-by-5 front stage\n");
+               buf[0] = 0x8a;          /* Disable divide-by-5. */
+               if (send_buf(ftdic, buf, 1)) {
+                       ret = -5;
+                       goto ftdi_err;
+               }
+               mpsse_clk = 60.0;
+       } else {
+               mpsse_clk = 12.0;
+       }
+
+       msg_pdbg("Set clock divisor\n");
+       buf[0] = 0x86;          /* command "set divisor" */
+       buf[1] = (divisor / 2 - 1) & 0xff;
+       buf[2] = ((divisor / 2 - 1) >> 8) & 0xff;
+       if (send_buf(ftdic, buf, 3)) {
+               ret = -6;
+               goto ftdi_err;
+       }
+
+       msg_pdbg("MPSSE clock: %f MHz, divisor: %u, SPI clock: %f MHz\n",
+                mpsse_clk, divisor, (double)(mpsse_clk / divisor));
+
+       /* 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)) {
+               ret = -7;
+               goto ftdi_err;
+       }
+
+       msg_pdbg("Set data bits\n");
+       buf[0] = SET_BITS_LOW;
+       buf[1] = cs_bits;
+       buf[2] = pindir;
+       if (send_buf(ftdic, buf, 3)) {
+               ret = -8;
+               goto ftdi_err;
+       }
+
+       // msg_pdbg("\nft2232 chosen\n");
+
+       register_spi_programmer(&spi_programmer_ft2232);
+
+       return 0;
+
+ftdi_err:
+       if ((f = ftdi_usb_close(ftdic)) < 0) {
+               msg_perr("Unable to close FTDI device: %d (%s)\n", f,
+                        ftdi_get_error_string(ftdic));
+       }
+
+       return ret;
+}
+
+/* Returns 0 upon success, a negative number upon errors. */
+static int ft2232_spi_send_command(struct flashctx *flash,
+                                  unsigned int writecnt, unsigned int readcnt,
+                                  const unsigned char *writearr,
+                                  unsigned char *readarr)
+{
+       struct ftdi_context *ftdic = &ftdic_context;
+       static unsigned char *buf = NULL;
+       /* 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 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");
+                       /* TODO: What to do with buf? */
+                       return SPI_GENERIC_ERROR;
+               }
+               oldbufsize = bufsize;
+       }
+
+       /*
+        * 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++] = 0 & ~cs_bits; /* assertive */
+       buf[i++] = pindir;
+
+       if (writecnt) {
+               buf[i++] = 0x11;
+               buf[i++] = (writecnt - 1) & 0xff;
+               buf[i++] = ((writecnt - 1) >> 8) & 0xff;
+               memcpy(buf + i, writearr, writecnt);
+               i += writecnt;
+       }
+
+       /*
+        * Optionally terminate this batch of commands with a
+        * read command, then do the fetch of the results.
+        */
+       if (readcnt) {
+               buf[i++] = 0x20;
+               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 == 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);
+               }
+       }
+
+       msg_pspew("De-assert CS#\n");
+       buf[i++] = SET_BITS_LOW;
+       buf[i++] = cs_bits;
+       buf[i++] = pindir;
+       ret = send_buf(ftdic, buf, i);
+       failed |= ret;
+       if (ret)
+               msg_perr("send_buf failed at end: %i\n", ret);
+
+       return failed ? -1 : 0;
+}
+
+void print_supported_usbdevs(const struct usbdev_status *devs)
+{
+       int i;
+
+       msg_pinfo("USB devices:\n");
+       for (i = 0; devs[i].vendor_name != NULL; i++) {
+               msg_pinfo("%s %s [%04x:%04x]%s\n", devs[i].vendor_name,
+                         devs[i].device_name, devs[i].vendor_id,
+                         devs[i].device_id,
+                         (devs[i].status == NT) ? " (untested)" : "");
+       }
+}
+
+#endif
diff --git a/gfxnvidia.c b/gfxnvidia.c
new file mode 100644 (file)
index 0000000..782d692
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_NVIDIA   0x10de
+
+/* Mask to restrict flash accesses to a 128kB memory window.
+ * FIXME: Is this size a one-fits-all or card dependent?
+ */
+#define GFXNVIDIA_MEMMAP_MASK          ((1 << 17) - 1)
+#define GFXNVIDIA_MEMMAP_SIZE          (16 * 1024 * 1024)
+
+uint8_t *nvidia_bar;
+
+const 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" },
+
+       {},
+};
+
+static void gfxnvidia_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                 chipaddr addr);
+static uint8_t gfxnvidia_chip_readb(const struct flashctx *flash,
+                                   const chipaddr addr);
+static const struct par_programmer par_programmer_gfxnvidia = {
+               .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,
+};
+
+static int gfxnvidia_shutdown(void *data)
+{
+       physunmap(nvidia_bar, GFXNVIDIA_MEMMAP_SIZE);
+       /* Flash interface access is disabled (and screen enabled) automatically
+        * by PCI restore.
+        */
+       pci_cleanup(pacc);
+       return 0;
+}
+
+int gfxnvidia_init(void)
+{
+       uint32_t reg32;
+
+       if (rget_io_perms())
+               return 1;
+
+       io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, gfx_nvidia);
+
+       io_base_addr += 0x300000;
+       msg_pinfo("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr);
+
+       nvidia_bar = physmap("NVIDIA", io_base_addr, GFXNVIDIA_MEMMAP_SIZE);
+
+       /* Must be done before rpci calls. */
+       if (register_shutdown(gfxnvidia_shutdown, NULL))
+               return 1;
+
+       /* Allow access to flash interface (will disable screen). */
+       reg32 = pci_read_long(pcidev_dev, 0x50);
+       reg32 &= ~(1 << 0);
+       rpci_write_long(pcidev_dev, 0x50, reg32);
+
+       /* Write/erase doesn't work. */
+       programmer_may_write = 0;
+       register_par_programmer(&par_programmer_gfxnvidia, BUS_PARALLEL);
+
+       return 0;
+}
+
+static void gfxnvidia_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                 chipaddr addr)
+{
+       pci_mmio_writeb(val, nvidia_bar + (addr & GFXNVIDIA_MEMMAP_MASK));
+}
+
+static uint8_t gfxnvidia_chip_readb(const struct flashctx *flash,
+                                   const chipaddr addr)
+{
+       return pci_mmio_readb(nvidia_bar + (addr & GFXNVIDIA_MEMMAP_MASK));
+}
diff --git a/hwaccess.c b/hwaccess.c
new file mode 100644 (file)
index 0000000..c18a110
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * 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 <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#if !defined (__DJGPP__) && !defined(__LIBPAYLOAD__)
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#if !defined (__DJGPP__)
+#include <errno.h>
+#endif
+#include "flash.h"
+#include "hwaccess.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* sync primitive is not needed because x86 uses uncached accesses
+ * which have a strongly ordered memory model.
+ */
+static inline void sync_primitive(void)
+{
+}
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+int io_fd;
+#endif
+
+int release_io_perms(void *p)
+{
+#if defined(__DJGPP__) || defined(__LIBPAYLOAD__)
+#else
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+       sysi86(SI86V86, V86SC_IOPL, 0);
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__DragonFly__)
+       close(io_fd);
+#else 
+       iopl(0);
+#endif
+#endif
+       return 0;
+}
+
+/* Get I/O permissions with automatic permission release on shutdown. */
+int rget_io_perms(void)
+{
+#if defined(__DJGPP__) || defined(__LIBPAYLOAD__)
+       /* We have full permissions by default. */
+       return 0;
+#else
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+       if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__DragonFly__)
+       if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
+#else 
+       if (iopl(3) != 0) {
+#endif
+               msg_perr("ERROR: Could not get I/O privileges (%s).\n"
+                       "You need to be root.\n", strerror(errno));
+#if defined (__OpenBSD__)
+               msg_perr("Please set securelevel=-1 in /etc/rc.securelevel "
+                          "and reboot, or reboot into \n");
+               msg_perr("single user mode.\n");
+#endif
+               return 1;
+       } else {
+               register_shutdown(release_io_perms, NULL);
+       }
+       return 0;
+#endif
+}
+
+#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__)
+
+static inline void sync_primitive(void)
+{
+       /* Prevent reordering and/or merging of reads/writes to hardware.
+        * Such reordering and/or merging would break device accesses which
+        * depend on the exact access order.
+        */
+       asm("eieio" : : : "memory");
+}
+
+/* PCI port I/O is not yet implemented on PowerPC. */
+int rget_io_perms(void)
+{
+       return 0;
+}
+
+#elif defined (__mips) || defined (__mips__) || defined (_mips) || defined (mips)
+
+/* sync primitive is not needed because /dev/mem on MIPS uses uncached accesses
+ * in mode 2 which has a strongly ordered memory model.
+ */
+static inline void sync_primitive(void)
+{
+}
+
+/* PCI port I/O is not yet implemented on MIPS. */
+int rget_io_perms(void)
+{
+       return 0;
+}
+
+#elif defined (__arm__)
+
+static inline void sync_primitive(void)
+{
+}
+
+int rget_io_perms(void)
+{
+       return 0;
+}
+
+#else
+
+#error Unknown architecture
+
+#endif
+
+void mmio_writeb(uint8_t val, void *addr)
+{
+       *(volatile uint8_t *) addr = val;
+       sync_primitive();
+}
+
+void mmio_writew(uint16_t val, void *addr)
+{
+       *(volatile uint16_t *) addr = val;
+       sync_primitive();
+}
+
+void mmio_writel(uint32_t val, void *addr)
+{
+       *(volatile uint32_t *) addr = val;
+       sync_primitive();
+}
+
+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 mmio_readn(void *addr, uint8_t *buf, size_t len)
+{
+       memcpy(buf, addr, len);
+       return;
+}
+
+void mmio_le_writeb(uint8_t val, void *addr)
+{
+       mmio_writeb(cpu_to_le8(val), addr);
+}
+
+void mmio_le_writew(uint16_t val, void *addr)
+{
+       mmio_writew(cpu_to_le16(val), addr);
+}
+
+void mmio_le_writel(uint32_t val, void *addr)
+{
+       mmio_writel(cpu_to_le32(val), addr);
+}
+
+uint8_t mmio_le_readb(void *addr)
+{
+       return le_to_cpu8(mmio_readb(addr));
+}
+
+uint16_t mmio_le_readw(void *addr)
+{
+       return le_to_cpu16(mmio_readw(addr));
+}
+
+uint32_t mmio_le_readl(void *addr)
+{
+       return le_to_cpu32(mmio_readl(addr));
+}
+
+enum mmio_write_type {
+       mmio_write_type_b,
+       mmio_write_type_w,
+       mmio_write_type_l,
+};
+
+struct undo_mmio_write_data {
+       void *addr;
+       int reg;
+       enum mmio_write_type type;
+       union {
+               uint8_t bdata;
+               uint16_t wdata;
+               uint32_t ldata;
+       };
+};
+
+int undo_mmio_write(void *p)
+{
+       struct undo_mmio_write_data *data = p;
+       msg_pdbg("Restoring MMIO space at %p\n", data->addr);
+       switch (data->type) {
+       case mmio_write_type_b:
+               mmio_writeb(data->bdata, data->addr);
+               break;
+       case mmio_write_type_w:
+               mmio_writew(data->wdata, data->addr);
+               break;
+       case mmio_write_type_l:
+               mmio_writel(data->ldata, data->addr);
+               break;
+       }
+       /* p was allocated in register_undo_mmio_write. */
+       free(p);
+       return 0;
+}
+
+#define register_undo_mmio_write(a, c)                                 \
+{                                                                      \
+       struct undo_mmio_write_data *undo_mmio_write_data;              \
+       undo_mmio_write_data = malloc(sizeof(struct undo_mmio_write_data)); \
+       if (!undo_mmio_write_data) {                                    \
+               msg_gerr("Out of memory!\n");                           \
+               exit(1);                                                \
+       }                                                               \
+       undo_mmio_write_data->addr = a;                                 \
+       undo_mmio_write_data->type = mmio_write_type_##c;               \
+       undo_mmio_write_data->c##data = mmio_read##c(a);                \
+       register_shutdown(undo_mmio_write, undo_mmio_write_data);       \
+}
+
+#define register_undo_mmio_writeb(a) register_undo_mmio_write(a, b)
+#define register_undo_mmio_writew(a) register_undo_mmio_write(a, w)
+#define register_undo_mmio_writel(a) register_undo_mmio_write(a, l)
+
+void rmmio_writeb(uint8_t val, void *addr)
+{
+       register_undo_mmio_writeb(addr);
+       mmio_writeb(val, addr);
+}
+
+void rmmio_writew(uint16_t val, void *addr)
+{
+       register_undo_mmio_writew(addr);
+       mmio_writew(val, addr);
+}
+
+void rmmio_writel(uint32_t val, void *addr)
+{
+       register_undo_mmio_writel(addr);
+       mmio_writel(val, addr);
+}
+
+void rmmio_le_writeb(uint8_t val, void *addr)
+{
+       register_undo_mmio_writeb(addr);
+       mmio_le_writeb(val, addr);
+}
+
+void rmmio_le_writew(uint16_t val, void *addr)
+{
+       register_undo_mmio_writew(addr);
+       mmio_le_writew(val, addr);
+}
+
+void rmmio_le_writel(uint32_t val, void *addr)
+{
+       register_undo_mmio_writel(addr);
+       mmio_le_writel(val, addr);
+}
+
+void rmmio_valb(void *addr)
+{
+       register_undo_mmio_writeb(addr);
+}
+
+void rmmio_valw(void *addr)
+{
+       register_undo_mmio_writew(addr);
+}
+
+void rmmio_vall(void *addr)
+{
+       register_undo_mmio_writel(addr);
+}
diff --git a/hwaccess.h b/hwaccess.h
new file mode 100644 (file)
index 0000000..1e276ec
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * 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 (__i386__) || defined (__x86_64__)
+#if defined(__GLIBC__)
+#include <sys/io.h>
+#endif
+#endif
+
+#if NEED_PCI == 1
+/*
+ * libpci headers use the variable name "index" which triggers shadowing
+ * warnings on systems which have the index() function in a default #include
+ * or as builtin.
+ */
+#define index shadow_workaround_index
+#include <pci/pci.h>
+#undef index
+#endif
+
+#if defined (__i386__) || defined (__x86_64__)
+
+/* All x86 is little-endian. */
+#define __FLASHROM_LITTLE_ENDIAN__ 1
+
+#elif defined (__mips) || defined (__mips__) || defined (_mips) || defined (mips)
+
+/* MIPS can be either endian. */
+#if defined (__MIPSEL) || defined (__MIPSEL__) || defined (_MIPSEL) || defined (MIPSEL)
+#define __FLASHROM_LITTLE_ENDIAN__ 1
+#elif defined (__MIPSEB) || defined (__MIPSEB__) || defined (_MIPSEB) || defined (MIPSEB)
+#define __FLASHROM_BIG_ENDIAN__ 1
+#endif
+
+#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__)
+
+/* PowerPC can be either endian. */
+#if defined (_BIG_ENDIAN) || defined (__BIG_ENDIAN__)
+#define __FLASHROM_BIG_ENDIAN__ 1
+/* Error checking in case some weird header has #defines for LE as well. */
+#if defined (_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__)
+#error Conflicting endianness #define
+#endif
+#else
+#error Little-endian PowerPC #defines are unknown
+#endif
+
+#elif defined (__arm__)
+#if defined (__ARMEL__)
+#define __FLASHROM_LITTLE_ENDIAN__ 1
+#else
+#error Big-endian ARM #defines are unknown
+#endif
+
+#endif
+
+#if !defined (__FLASHROM_BIG_ENDIAN__) && !defined (__FLASHROM_LITTLE_ENDIAN__)
+/* Nonstandard libc-specific macros for determining endianness. */
+#if defined(__GLIBC__)
+#include <endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define __FLASHROM_LITTLE_ENDIAN__ 1
+#elif BYTE_ORDER == BIG_ENDIAN
+#define __FLASHROM_BIG_ENDIAN__ 1
+#endif
+#endif
+#endif
+
+#if !defined (__FLASHROM_BIG_ENDIAN__) && !defined (__FLASHROM_LITTLE_ENDIAN__)
+#error Unable to determine endianness. Please add support for your arch or libc.
+#endif
+
+#define ___constant_swab8(x) ((uint8_t) (                              \
+       (((uint8_t)(x) & (uint8_t)0xffU))))
+
+#define ___constant_swab16(x) ((uint16_t) (                            \
+       (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) |                    \
+       (((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))
+
+#define ___constant_swab32(x) ((uint32_t) (                            \
+       (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) |              \
+       (((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) |              \
+       (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) |              \
+       (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
+
+#define ___constant_swab64(x) ((uint64_t) (                            \
+       (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) |     \
+       (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) |     \
+       (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) |     \
+       (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) <<  8) |     \
+       (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >>  8) |     \
+       (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) |     \
+       (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) |     \
+       (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56)))
+
+#if defined (__FLASHROM_BIG_ENDIAN__)
+
+#define cpu_to_le(bits)                                                        \
+static inline uint##bits##_t cpu_to_le##bits(uint##bits##_t val)       \
+{                                                                      \
+       return ___constant_swab##bits(val);                             \
+}
+
+cpu_to_le(8)
+cpu_to_le(16)
+cpu_to_le(32)
+cpu_to_le(64)
+
+#define cpu_to_be8
+#define cpu_to_be16
+#define cpu_to_be32
+#define cpu_to_be64
+
+#elif defined (__FLASHROM_LITTLE_ENDIAN__)
+
+#define cpu_to_be(bits)                                                        \
+static inline uint##bits##_t cpu_to_be##bits(uint##bits##_t val)       \
+{                                                                      \
+       return ___constant_swab##bits(val);                             \
+}
+
+cpu_to_be(8)
+cpu_to_be(16)
+cpu_to_be(32)
+cpu_to_be(64)
+
+#define cpu_to_le8
+#define cpu_to_le16
+#define cpu_to_le32
+#define cpu_to_le64
+
+#else
+
+#error Could not determine endianness.
+
+#endif
+
+#define be_to_cpu8 cpu_to_be8
+#define be_to_cpu16 cpu_to_be16
+#define be_to_cpu32 cpu_to_be32
+#define be_to_cpu64 cpu_to_be64
+#define le_to_cpu8 cpu_to_le8
+#define le_to_cpu16 cpu_to_le16
+#define le_to_cpu32 cpu_to_le32
+#define le_to_cpu64 cpu_to_le64
+
+#if NEED_PCI == 1
+#if defined (__i386__) || defined (__x86_64__)
+
+#define __FLASHROM_HAVE_OUTB__ 1
+
+/* for iopl and outb under Solaris */
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+#include <strings.h>
+#include <sys/sysi86.h>
+#include <sys/psw.h>
+#include <asm/sunddi.h>
+#endif
+
+#if (defined(__MACH__) && defined(__APPLE__))
+#define __DARWIN__
+#endif
+
+/* Clarification about OUTB/OUTW/OUTL argument order:
+ * OUT[BWL](val, port)
+ */
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+  /* Note that Debian/kFreeBSD (FreeBSD kernel with glibc) has conflicting
+   * out[bwl] definitions in machine/cpufunc.h and sys/io.h at least in some
+   * versions. Use machine/cpufunc.h only for plain FreeBSD/DragonFlyBSD.
+   */
+  #include <machine/cpufunc.h>
+  #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__)
+    /* Header is part of the DirectHW library. */
+    #include <DirectHW/DirectHW.h>
+    #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 <pc.h>
+
+  #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
+  /* This is the usual glibc interface. */
+  #define OUTB outb
+  #define OUTW outw
+  #define OUTL outl
+  #define INB  inb
+  #define INW  inw
+  #define INL  inl
+
+#endif
+
+#endif
+#endif
+
+#if defined(__NetBSD__) || defined (__OpenBSD__)
+  #define off64_t off_t
+  #define lseek64 lseek
+  #if defined(__i386__) || defined(__x86_64__)
+    #include <sys/types.h>
+    #include <machine/sysarch.h>
+#if defined(__NetBSD__)
+    #if defined(__i386__)
+      #define iopl i386_iopl
+    #elif defined(__x86_64__)
+      #define iopl x86_64_iopl
+    #endif
+#elif defined (__OpenBSD__)
+    #if defined(__i386__)
+      #define iopl i386_iopl
+    #elif defined(__amd64__)
+      #define iopl amd64_iopl
+    #endif
+#endif
+
+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(__FreeBSD_kernel__) && !defined(__DragonFly__) && !defined(__LIBPAYLOAD__)
+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(__FreeBSD_kernel__) || 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
+#if defined(__LIBPAYLOAD__)
+#include <arch/io.h>
+#include <arch/msr.h>
+typedef struct { uint32_t hi, lo; } msr_t;
+msr_t libpayload_rdmsr(int addr);
+int libpayload_wrmsr(int addr, msr_t msr);
+#undef rdmsr
+#define rdmsr libpayload_rdmsr
+#define wrmsr libpayload_wrmsr
+#endif
+
+#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__)
+
+/* PCI port I/O is not yet implemented on PowerPC. */
+
+#elif defined (__mips) || defined (__mips__) || defined (_mips) || defined (mips)
+
+/* PCI port I/O is not yet implemented on MIPS. */
+
+#elif defined(__arm__)
+
+/* Non memory mapped I/O is not supported on ARM. */
+
+#else
+
+#error Unknown architecture, please check if it supports PCI port IO.
+
+#endif
+#endif
+
+#endif /* !__HWACCESS_H__ */
diff --git a/ich_descriptors.c b/ich_descriptors.c
new file mode 100644 (file)
index 0000000..b55625e
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (c) 2010  Matthias Wenzel <bios at mazzoo dot de>
+ * Copyright (c) 2011  Stefan Tauner
+ *
+ * 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
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "ich_descriptors.h"
+
+#ifdef ICH_DESCRIPTORS_FROM_DUMP
+
+#include <stdio.h>
+#define print(t, ...) printf(__VA_ARGS__)
+#define DESCRIPTOR_MODE_SIGNATURE 0x0ff0a55a
+/* The upper map is located in the word before the 256B-long OEM section at the
+ * end of the 4kB-long flash descriptor.
+ */
+#define UPPER_MAP_OFFSET (4096 - 256 - 4)
+#define getVTBA(flumap)        (((flumap)->FLUMAP1 << 4) & 0x00000ff0)
+
+#else /* ICH_DESCRIPTORS_FROM_DUMP */
+
+#include "flash.h" /* for msg_* */
+#include "programmer.h"
+
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */
+
+#ifndef min
+#define min(a, b) (a < b) ? a : b
+#endif
+
+void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity)
+{
+       print(verbosity, "BES=0x%x, ",  (reg_val & VSCC_BES)  >> VSCC_BES_OFF);
+       print(verbosity, "WG=%d, ",     (reg_val & VSCC_WG)   >> VSCC_WG_OFF);
+       print(verbosity, "WSR=%d, ",    (reg_val & VSCC_WSR)  >> VSCC_WSR_OFF);
+       print(verbosity, "WEWS=%d, ",   (reg_val & VSCC_WEWS) >> VSCC_WEWS_OFF);
+       print(verbosity, "EO=0x%x, ",   (reg_val & VSCC_EO)   >> VSCC_EO_OFF);
+       print(verbosity, "VCL=%d\n",    (reg_val & VSCC_VCL)  >> VSCC_VCL_OFF);
+}
+
+#define getFCBA(cont)  (((cont)->FLMAP0 <<  4) & 0x00000ff0)
+#define getFRBA(cont)  (((cont)->FLMAP0 >> 12) & 0x00000ff0)
+#define getFMBA(cont)  (((cont)->FLMAP1 <<  4) & 0x00000ff0)
+#define getFISBA(cont) (((cont)->FLMAP1 >> 12) & 0x00000ff0)
+#define getFMSBA(cont) (((cont)->FLMAP2 <<  4) & 0x00000ff0)
+
+void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descriptors *desc)
+{
+       prettyprint_ich_descriptor_content(&desc->content);
+       prettyprint_ich_descriptor_component(desc);
+       prettyprint_ich_descriptor_region(desc);
+       prettyprint_ich_descriptor_master(&desc->master);
+#ifdef ICH_DESCRIPTORS_FROM_DUMP
+       if (cs >= CHIPSET_ICH8) {
+               prettyprint_ich_descriptor_upper_map(&desc->upper);
+               prettyprint_ich_descriptor_straps(cs, desc);
+       }
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */
+}
+
+void prettyprint_ich_descriptor_content(const struct ich_desc_content *cont)
+{
+       msg_pdbg2("=== Content Section ===\n");
+       msg_pdbg2("FLVALSIG 0x%08x\n", cont->FLVALSIG);
+       msg_pdbg2("FLMAP0   0x%08x\n", cont->FLMAP0);
+       msg_pdbg2("FLMAP1   0x%08x\n", cont->FLMAP1);
+       msg_pdbg2("FLMAP2   0x%08x\n", cont->FLMAP2);
+       msg_pdbg2("\n");
+
+       msg_pdbg2("--- Details ---\n");
+       msg_pdbg2("NR          (Number of Regions):                 %5d\n",
+                 cont->NR + 1);
+       msg_pdbg2("FRBA        (Flash Region Base Address):         0x%03x\n",
+                 getFRBA(cont));
+       msg_pdbg2("NC          (Number of Components):              %5d\n",
+                 cont->NC + 1);
+       msg_pdbg2("FCBA        (Flash Component Base Address):      0x%03x\n",
+                 getFCBA(cont));
+       msg_pdbg2("ISL         (ICH/PCH Strap Length):              %5d\n",
+                 cont->ISL);
+       msg_pdbg2("FISBA/FPSBA (Flash ICH/PCH Strap Base Address):  0x%03x\n",
+                 getFISBA(cont));
+       msg_pdbg2("NM          (Number of Masters):                 %5d\n",
+                 cont->NM + 1);
+       msg_pdbg2("FMBA        (Flash Master Base Address):         0x%03x\n",
+                 getFMBA(cont));
+       msg_pdbg2("MSL/PSL     (MCH/PROC Strap Length):             %5d\n",
+                 cont->MSL);
+       msg_pdbg2("FMSBA       (Flash MCH/PROC Strap Base Address): 0x%03x\n",
+                 getFMSBA(cont));
+       msg_pdbg2("\n");
+}
+
+void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc)
+{
+       static const char * const freq_str[8] = {
+               "20 MHz",       /* 000 */
+               "33 MHz",       /* 001 */
+               "reserved",     /* 010 */
+               "reserved",     /* 011 */
+               "50 MHz",       /* 100 */
+               "reserved",     /* 101 */
+               "reserved",     /* 110 */
+               "reserved"      /* 111 */
+       };
+       static const char * const size_str[8] = {
+               "512 kB",       /* 000 */
+               "  1 MB",       /* 001 */
+               "  2 MB",       /* 010 */
+               "  4 MB",       /* 011 */
+               "  8 MB",       /* 100 */
+               " 16 MB",       /* 101 */
+               "reserved",     /* 110 */
+               "reserved",     /* 111 */
+       };
+
+       msg_pdbg2("=== Component Section ===\n");
+       msg_pdbg2("FLCOMP   0x%08x\n", desc->component.FLCOMP);
+       msg_pdbg2("FLILL    0x%08x\n", desc->component.FLILL );
+       msg_pdbg2("\n");
+
+       msg_pdbg2("--- Details ---\n");
+       msg_pdbg2("Component 1 density:           %s\n",
+                 size_str[desc->component.comp1_density]);
+       if (desc->content.NC)
+               msg_pdbg2("Component 2 density:           %s\n",
+                         size_str[desc->component.comp2_density]);
+       else
+               msg_pdbg2("Component 2 is not used.\n");
+       msg_pdbg2("Read Clock Frequency:           %s\n",
+                 freq_str[desc->component.freq_read]);
+       msg_pdbg2("Read ID and Status Clock Freq.: %s\n",
+                 freq_str[desc->component.freq_read_id]);
+       msg_pdbg2("Write and Erase Clock Freq.:    %s\n",
+                 freq_str[desc->component.freq_write]);
+       msg_pdbg2("Fast Read is %ssupported.\n",
+                 desc->component.fastread ? "" : "not ");
+       if (desc->component.fastread)
+               msg_pdbg2("Fast Read Clock Frequency:      %s\n",
+                         freq_str[desc->component.freq_fastread]);
+       if (desc->component.FLILL == 0)
+               msg_pdbg2("No forbidden opcodes.\n");
+       else {
+               msg_pdbg2("Invalid instruction 0:          0x%02x\n",
+                         desc->component.invalid_instr0);
+               msg_pdbg2("Invalid instruction 1:          0x%02x\n",
+                         desc->component.invalid_instr1);
+               msg_pdbg2("Invalid instruction 2:          0x%02x\n",
+                         desc->component.invalid_instr2);
+               msg_pdbg2("Invalid instruction 3:          0x%02x\n",
+                         desc->component.invalid_instr3);
+       }
+       msg_pdbg2("\n");
+}
+
+static void pprint_freg(const struct ich_desc_region *reg, uint32_t i)
+{
+       static const char *const region_names[5] = {
+               "Descr.", "BIOS", "ME", "GbE", "Platf."
+       };
+       if (i >= 5) {
+               msg_pdbg2("%s: region index too high.\n", __func__);
+               return;
+       }
+       uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]);
+       uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]);
+       msg_pdbg2("Region %d (%-6s) ", i, region_names[i]);
+       if (base > limit)
+               msg_pdbg2("is unused.\n");
+       else
+               msg_pdbg2("0x%08x - 0x%08x\n", base, limit | 0x0fff);
+}
+
+void prettyprint_ich_descriptor_region(const struct ich_descriptors *desc)
+{
+       uint8_t i;
+       uint8_t nr = desc->content.NR + 1;
+       msg_pdbg2("=== Region Section ===\n");
+       if (nr > 5) {
+               msg_pdbg2("%s: number of regions too high (%d).\n", __func__,
+                        nr);
+               return;
+       }
+       for (i = 0; i <= nr; i++)
+               msg_pdbg2("FLREG%d   0x%08x\n", i, desc->region.FLREGs[i]);
+       msg_pdbg2("\n");
+
+       msg_pdbg2("--- Details ---\n");
+       for (i = 0; i <= nr; i++)
+               pprint_freg(&desc->region, i);
+       msg_pdbg2("\n");
+}
+
+void prettyprint_ich_descriptor_master(const struct ich_desc_master *mstr)
+{
+       msg_pdbg2("=== Master Section ===\n");
+       msg_pdbg2("FLMSTR1  0x%08x\n", mstr->FLMSTR1);
+       msg_pdbg2("FLMSTR2  0x%08x\n", mstr->FLMSTR2);
+       msg_pdbg2("FLMSTR3  0x%08x\n", mstr->FLMSTR3);
+       msg_pdbg2("\n");
+
+       msg_pdbg2("--- Details ---\n");
+       msg_pdbg2("      Descr. BIOS ME GbE Platf.\n");
+       msg_pdbg2("BIOS    %c%c    %c%c  %c%c  %c%c   %c%c\n",
+       (mstr->BIOS_descr_r)    ?'r':' ', (mstr->BIOS_descr_w)  ?'w':' ',
+       (mstr->BIOS_BIOS_r)     ?'r':' ', (mstr->BIOS_BIOS_w)   ?'w':' ',
+       (mstr->BIOS_ME_r)       ?'r':' ', (mstr->BIOS_ME_w)     ?'w':' ',
+       (mstr->BIOS_GbE_r)      ?'r':' ', (mstr->BIOS_GbE_w)    ?'w':' ',
+       (mstr->BIOS_plat_r)     ?'r':' ', (mstr->BIOS_plat_w)   ?'w':' ');
+       msg_pdbg2("ME      %c%c    %c%c  %c%c  %c%c   %c%c\n",
+       (mstr->ME_descr_r)      ?'r':' ', (mstr->ME_descr_w)    ?'w':' ',
+       (mstr->ME_BIOS_r)       ?'r':' ', (mstr->ME_BIOS_w)     ?'w':' ',
+       (mstr->ME_ME_r)         ?'r':' ', (mstr->ME_ME_w)       ?'w':' ',
+       (mstr->ME_GbE_r)        ?'r':' ', (mstr->ME_GbE_w)      ?'w':' ',
+       (mstr->ME_plat_r)       ?'r':' ', (mstr->ME_plat_w)     ?'w':' ');
+       msg_pdbg2("GbE     %c%c    %c%c  %c%c  %c%c   %c%c\n",
+       (mstr->GbE_descr_r)     ?'r':' ', (mstr->GbE_descr_w)   ?'w':' ',
+       (mstr->GbE_BIOS_r)      ?'r':' ', (mstr->GbE_BIOS_w)    ?'w':' ',
+       (mstr->GbE_ME_r)        ?'r':' ', (mstr->GbE_ME_w)      ?'w':' ',
+       (mstr->GbE_GbE_r)       ?'r':' ', (mstr->GbE_GbE_w)     ?'w':' ',
+       (mstr->GbE_plat_r)      ?'r':' ', (mstr->GbE_plat_w)    ?'w':' ');
+       msg_pdbg2("\n");
+}
+
+#ifdef ICH_DESCRIPTORS_FROM_DUMP
+
+void prettyprint_ich_descriptor_straps_ich8(const struct ich_descriptors *desc)
+{
+       static const char * const str_GPIO12[4] = {
+               "GPIO12",
+               "LAN PHY Power Control Function (Native Output)",
+               "GLAN_DOCK# (Native Input)",
+               "invalid configuration",
+       };
+
+       msg_pdbg2("--- MCH details ---\n");
+       msg_pdbg2("ME B is %sabled.\n", desc->north.ich8.MDB ? "dis" : "en");
+       msg_pdbg2("\n");
+
+       msg_pdbg2("--- ICH details ---\n");
+       msg_pdbg2("ME SMBus Address 1: 0x%02x\n", desc->south.ich8.ASD);
+       msg_pdbg2("ME SMBus Address 2: 0x%02x\n", desc->south.ich8.ASD2);
+       msg_pdbg2("ME SMBus Controller is connected to the %s.\n",
+                 desc->south.ich8.MESM2SEL ? "SMLink pins" : "SMBus pins");
+       msg_pdbg2("SPI CS1 is used for %s.\n",
+                 desc->south.ich8.SPICS1_LANPHYPC_SEL ?
+                 "LAN PHY Power Control Function" :
+                 "SPI Chip Select");
+       msg_pdbg2("GPIO12 is used as %s.\n",
+                 str_GPIO12[desc->south.ich8.GPIO12_SEL]);
+       msg_pdbg2("PCIe Port 6 is used for %s.\n",
+            desc->south.ich8.GLAN_PCIE_SEL ? "integrated LAN" : "PCI Express");
+       msg_pdbg2("%sn BMC Mode: "
+                 "Intel AMT SMBus Controller 1 is connected to %s.\n",
+                 desc->south.ich8.BMCMODE ? "I" : "Not i",
+                 desc->south.ich8.BMCMODE ? "SMLink" : "SMBus");
+       msg_pdbg2("TCO is in %s Mode.\n",
+              desc->south.ich8.TCOMODE ? "Advanced TCO" : "Legacy/Compatible");
+       msg_pdbg2("ME A is %sabled.\n",
+                 desc->south.ich8.ME_DISABLE ? "dis" : "en");
+       msg_pdbg2("\n");
+}
+
+static void prettyprint_ich_descriptor_straps_56_pciecs(uint8_t conf, uint8_t off)
+{
+       msg_pdbg2("PCI Express Port Configuration Strap %d: ", off+1);
+
+       off *= 4;
+       switch(conf){
+       case 0:
+               msg_pdbg2("4x1 Ports %d-%d (x1)", 1+off, 4+off);
+               break;
+       case 1:
+               msg_pdbg2("1x2, 2x1 Port %d (x2), Port %d (disabled), "
+                         "Ports %d, %d (x1)", 1+off, 2+off, 3+off, 4+off);
+               break;
+       case 2:
+               msg_pdbg2("2x2 Port %d (x2), Port %d (x2), Ports "
+                         "%d, %d (disabled)", 1+off, 3+off, 2+off, 4+off);
+               break;
+       case 3:
+               msg_pdbg2("1x4 Port %d (x4), Ports %d-%d (disabled)",
+                         1+off, 2+off, 4+off);
+               break;
+       }
+       msg_pdbg2("\n");
+}
+
+void prettyprint_ich_descriptor_pchstraps45678_56(const struct ich_desc_south_strap *s)
+{
+       /* PCHSTRP4 */
+       msg_pdbg2("Intel PHY is %s.\n",
+                 (s->ibex.PHYCON == 2) ? "connected" :
+                         (s->ibex.PHYCON == 0) ? "disconnected" : "reserved");
+       msg_pdbg2("GbE MAC SMBus address is %sabled.\n",
+                 s->ibex.GBEMAC_SMBUS_ADDR_EN ? "en" : "dis");
+       msg_pdbg2("GbE MAC SMBus address: 0x%02x\n",
+                 s->ibex.GBEMAC_SMBUS_ADDR);
+       msg_pdbg2("GbE PHY SMBus address: 0x%02x\n",
+                 s->ibex.GBEPHY_SMBUS_ADDR);
+
+       /* PCHSTRP5 */
+       /* PCHSTRP6 */
+       /* PCHSTRP7 */
+       msg_pdbg2("Intel ME SMBus Subsystem Vendor ID: 0x%04x\n",
+                 s->ibex.MESMA2UDID_VENDOR);
+       msg_pdbg2("Intel ME SMBus Subsystem Device ID: 0x%04x\n",
+                 s->ibex.MESMA2UDID_VENDOR);
+
+       /* PCHSTRP8 */
+}
+
+void prettyprint_ich_descriptor_pchstraps111213_56(const struct ich_desc_south_strap *s)
+{
+       /* PCHSTRP11 */
+       msg_pdbg2("SMLink1 GP Address is %sabled.\n",
+                 s->ibex.SML1GPAEN ? "en" : "dis");
+       msg_pdbg2("SMLink1 controller General Purpose Target address: 0x%02x\n",
+                 s->ibex.SML1GPA);
+       msg_pdbg2("SMLink1 I2C Target address is %sabled.\n",
+                 s->ibex.SML1I2CAEN ? "en" : "dis");
+       msg_pdbg2("SMLink1 I2C Target address: 0x%02x\n",
+                 s->ibex.SML1I2CA);
+
+       /* PCHSTRP12 */
+       /* PCHSTRP13 */
+}
+
+void prettyprint_ich_descriptor_straps_ibex(const struct ich_desc_south_strap *s)
+{
+       static const uint8_t const dec_t209min[4] = {
+               100,
+               50,
+               5,
+               1
+       };
+
+       msg_pdbg2("--- PCH ---\n");
+
+       /* PCHSTRP0 */
+       msg_pdbg2("Chipset configuration Softstrap 2: %d\n", s->ibex.cs_ss2);
+       msg_pdbg2("Intel ME SMBus Select is %sabled.\n",
+                 s->ibex.SMB_EN ? "en" : "dis");
+       msg_pdbg2("SMLink0 segment is %sabled.\n",
+                 s->ibex.SML0_EN ? "en" : "dis");
+       msg_pdbg2("SMLink1 segment is %sabled.\n",
+                 s->ibex.SML1_EN ? "en" : "dis");
+       msg_pdbg2("SMLink1 Frequency: %s\n",
+                 (s->ibex.SML1FRQ == 1) ? "100 kHz" : "reserved");
+       msg_pdbg2("Intel ME SMBus Frequency: %s\n",
+                 (s->ibex.SMB0FRQ == 1) ? "100 kHz" : "reserved");
+       msg_pdbg2("SMLink0 Frequency: %s\n",
+                 (s->ibex.SML0FRQ == 1) ? "100 kHz" : "reserved");
+       msg_pdbg2("GPIO12 is used as %s.\n", s->ibex.LANPHYPC_GP12_SEL ?
+                 "LAN_PHY_PWR_CTRL" : "general purpose output");
+       msg_pdbg2("Chipset configuration Softstrap 1: %d\n", s->ibex.cs_ss1);
+       msg_pdbg2("DMI RequesterID Checks are %sabled.\n",
+                 s->ibex.DMI_REQID_DIS ? "en" : "dis");
+       msg_pdbg2("BIOS Boot-Block size (BBBS): %d kB.\n",
+                 1 << (6 + s->ibex.BBBS));
+
+       /* PCHSTRP1 */
+       msg_pdbg2("Chipset configuration Softstrap 3: 0x%x\n", s->ibex.cs_ss3);
+
+       /* PCHSTRP2 */
+       msg_pdbg2("ME SMBus ASD address is %sabled.\n",
+                 s->ibex.MESMASDEN ? "en" : "dis");
+       msg_pdbg2("ME SMBus Controller ASD Target address: 0x%02x\n",
+                 s->ibex.MESMASDA);
+       msg_pdbg2("ME SMBus I2C address is %sabled.\n",
+                 s->ibex.MESMI2CEN ? "en" : "dis");
+       msg_pdbg2("ME SMBus I2C target address: 0x%02x\n",
+                 s->ibex.MESMI2CA);
+
+       /* PCHSTRP3 */
+       prettyprint_ich_descriptor_pchstraps45678_56(s);
+       /* PCHSTRP9 */
+       prettyprint_ich_descriptor_straps_56_pciecs(s->ibex.PCIEPCS1, 0);
+       prettyprint_ich_descriptor_straps_56_pciecs(s->ibex.PCIEPCS1, 1);
+       msg_pdbg2("PCIe Lane Reversal 1: PCIe Lanes 0-3 are %sreserved.\n",
+                 s->ibex.PCIELR1 ? "" : "not ");
+       msg_pdbg2("PCIe Lane Reversal 2: PCIe Lanes 4-7 are %sreserved.\n",
+                 s->ibex.PCIELR2 ? "" : "not ");
+       msg_pdbg2("DMI Lane Reversal: DMI Lanes 0-3 are %sreserved.\n",
+                 s->ibex.DMILR ? "" : "not ");
+       msg_pdbg2("Default PHY PCIe Port is %d.\n", s->ibex.PHY_PCIEPORTSEL+1);
+       msg_pdbg2("Integrated MAC/PHY communication over PCIe is %sabled.\n",
+                 s->ibex.PHY_PCIE_EN ? "en" : "dis");
+
+       /* PCHSTRP10 */
+       msg_pdbg2("Management Engine will boot from %sflash.\n",
+                 s->ibex.ME_BOOT_FLASH ? "" : "ROM, then ");
+       msg_pdbg2("Chipset configuration Softstrap 5: %d\n", s->ibex.cs_ss5);
+       msg_pdbg2("Virtualization Engine Enable 1 is %sabled.\n",
+                 s->ibex.VE_EN ? "en" : "dis");
+       msg_pdbg2("ME Memory-attached Debug Display Device is %sabled.\n",
+                 s->ibex.MMDDE ? "en" : "dis");
+       msg_pdbg2("ME Memory-attached Debug Display Device address: 0x%02x\n",
+                 s->ibex.MMADDR);
+       msg_pdbg2("Chipset configuration Softstrap 7: %d\n", s->ibex.cs_ss7);
+       msg_pdbg2("Integrated Clocking Configuration is %d.\n",
+                 (s->ibex.ICC_SEL == 7) ? 0 : s->ibex.ICC_SEL);
+       msg_pdbg2("PCH Signal CL_RST1# does %sassert when Intel ME performs a "
+                 "reset.\n", s->ibex.MER_CL1 ? "" : "not ");
+
+       prettyprint_ich_descriptor_pchstraps111213_56(s);
+
+       /* PCHSTRP14 */
+       msg_pdbg2("Virtualization Engine Enable 2 is %sabled.\n",
+                 s->ibex.VE_EN2 ? "en" : "dis");
+       msg_pdbg2("Virtualization Engine will boot from %sflash.\n",
+                 s->ibex.VE_BOOT_FLASH ? "" : "ROM, then ");
+       msg_pdbg2("Braidwood SSD functionality is %sabled.\n",
+                 s->ibex.BW_SSD ? "en" : "dis");
+       msg_pdbg2("Braidwood NVMHCI functionality is %sabled.\n",
+                 s->ibex.NVMHCI_EN ? "en" : "dis");
+
+       /* PCHSTRP15 */
+       msg_pdbg2("Chipset configuration Softstrap 6: %d\n", s->ibex.cs_ss6);
+       msg_pdbg2("Integrated wired LAN Solution is %sabled.\n",
+                 s->ibex.IWL_EN ? "en" : "dis");
+       msg_pdbg2("t209 min Timing: %d ms\n",
+                 dec_t209min[s->ibex.t209min]);
+       msg_pdbg2("\n");
+}
+
+void prettyprint_ich_descriptor_straps_cougar(const struct ich_desc_south_strap *s)
+{
+       msg_pdbg2("--- PCH ---\n");
+
+       /* PCHSTRP0 */
+       msg_pdbg2("Chipset configuration Softstrap 1: %d\n", s->cougar.cs_ss1);
+       msg_pdbg2("Intel ME SMBus Select is %sabled.\n",
+                 s->ibex.SMB_EN ? "en" : "dis");
+       msg_pdbg2("SMLink0 segment is %sabled.\n",
+                 s->ibex.SML0_EN ? "en" : "dis");
+       msg_pdbg2("SMLink1 segment is %sabled.\n",
+                 s->ibex.SML1_EN ? "en" : "dis");
+       msg_pdbg2("SMLink1 Frequency: %s\n",
+                 (s->ibex.SML1FRQ == 1) ? "100 kHz" : "reserved");
+       msg_pdbg2("Intel ME SMBus Frequency: %s\n",
+                 (s->ibex.SMB0FRQ == 1) ? "100 kHz" : "reserved");
+       msg_pdbg2("SMLink0 Frequency: %s\n",
+                 (s->ibex.SML0FRQ == 1) ? "100 kHz" : "reserved");
+       msg_pdbg2("GPIO12 is used as %s.\n", s->ibex.LANPHYPC_GP12_SEL ?
+                 "LAN_PHY_PWR_CTRL" : "general purpose output");
+       msg_pdbg2("LinkSec is %sabled.\n",
+                 s->cougar.LINKSEC_DIS ? "en" : "dis");
+       msg_pdbg2("DMI RequesterID Checks are %sabled.\n",
+                 s->ibex.DMI_REQID_DIS ? "en" : "dis");
+       msg_pdbg2("BIOS Boot-Block size (BBBS): %d kB.\n",
+                 1 << (6 + s->ibex.BBBS));
+
+       /* PCHSTRP1 */
+       msg_pdbg2("Chipset configuration Softstrap 3: 0x%x\n", s->ibex.cs_ss3);
+       msg_pdbg2("Chipset configuration Softstrap 2: 0x%x\n", s->ibex.cs_ss2);
+
+       /* PCHSTRP2 */
+       msg_pdbg2("ME SMBus ASD address is %sabled.\n",
+                 s->ibex.MESMASDEN ? "en" : "dis");
+       msg_pdbg2("ME SMBus Controller ASD Target address: 0x%02x\n",
+                 s->ibex.MESMASDA);
+       msg_pdbg2("ME SMBus MCTP Address is %sabled.\n",
+                 s->cougar.MESMMCTPAEN ? "en" : "dis");
+       msg_pdbg2("ME SMBus MCTP target address: 0x%02x\n",
+                 s->cougar.MESMMCTPA);
+       msg_pdbg2("ME SMBus I2C address is %sabled.\n",
+                 s->ibex.MESMI2CEN ? "en" : "dis");
+       msg_pdbg2("ME SMBus I2C target address: 0x%02x\n",
+                 s->ibex.MESMI2CA);
+
+       /* PCHSTRP3 */
+       prettyprint_ich_descriptor_pchstraps45678_56(s);
+       /* PCHSTRP9 */
+       prettyprint_ich_descriptor_straps_56_pciecs(s->ibex.PCIEPCS1, 0);
+       prettyprint_ich_descriptor_straps_56_pciecs(s->ibex.PCIEPCS1, 1);
+       msg_pdbg2("PCIe Lane Reversal 1: PCIe Lanes 0-3 are %sreserved.\n",
+                 s->ibex.PCIELR1 ? "" : "not ");
+       msg_pdbg2("PCIe Lane Reversal 2: PCIe Lanes 4-7 are %sreserved.\n",
+                 s->ibex.PCIELR2 ? "" : "not ");
+       msg_pdbg2("DMI Lane Reversal: DMI Lanes 0-3 are %sreserved.\n",
+                 s->ibex.DMILR ? "" : "not ");
+       msg_pdbg2("ME Debug status writes over SMBUS are %sabled.\n",
+                 s->cougar.MDSMBE_EN ? "en" : "dis");
+       msg_pdbg2("ME Debug SMBus Emergency Mode address: 0x%02x (raw)\n",
+                 s->cougar.MDSMBE_ADD);
+       msg_pdbg2("Default PHY PCIe Port is %d.\n", s->ibex.PHY_PCIEPORTSEL+1);
+       msg_pdbg2("Integrated MAC/PHY communication over PCIe is %sabled.\n",
+                 s->ibex.PHY_PCIE_EN ? "en" : "dis");
+       msg_pdbg2("PCIe ports Subtractive Decode Agent is %sabled.\n",
+                 s->cougar.SUB_DECODE_EN ? "en" : "dis");
+       msg_pdbg2("GPIO74 is used as %s.\n", s->cougar.PCHHOT_SML1ALERT_SEL ?
+                 "PCHHOT#" : "SML1ALERT#");
+
+       /* PCHSTRP10 */
+       msg_pdbg2("Management Engine will boot from %sflash.\n",
+                 s->ibex.ME_BOOT_FLASH ? "" : "ROM, then ");
+
+       msg_pdbg2("ME Debug SMBus Emergency Mode is %sabled.\n",
+                 s->cougar.MDSMBE_EN ? "en" : "dis");
+       msg_pdbg2("ME Debug SMBus Emergency Mode Address: 0x%02x\n",
+                 s->cougar.MDSMBE_ADD);
+
+       msg_pdbg2("Integrated Clocking Configuration used: %d\n",
+                 s->cougar.ICC_SEL);
+       msg_pdbg2("PCH Signal CL_RST1# does %sassert when Intel ME performs a "
+                 "reset.\n", s->ibex.MER_CL1 ? "" : "not ");
+       msg_pdbg2("ICC Profile is selected by %s.\n",
+                 s->cougar.ICC_PRO_SEL ? "Softstraps" : "BIOS");
+       msg_pdbg2("Deep SX is %ssupported on the platform.\n",
+                 s->cougar.Deep_SX_EN ? "not " : "");
+       msg_pdbg2("ME Debug LAN Emergency Mode is %sabled.\n",
+                 s->cougar.ME_DBG_LAN ? "en" : "dis");
+
+       prettyprint_ich_descriptor_pchstraps111213_56(s);
+
+       /* PCHSTRP14 */
+       /* PCHSTRP15 */
+       msg_pdbg2("Chipset configuration Softstrap 6: %d\n", s->cougar.cs_ss6);
+       msg_pdbg2("Integrated wired LAN is %sabled.\n",
+                 s->cougar.IWL_EN ? "en" : "dis");
+       msg_pdbg2("Chipset configuration Softstrap 5: %d\n", s->cougar.cs_ss5);
+       msg_pdbg2("SMLink1 provides temperature from %s.\n",
+                 s->cougar.SMLINK1_THERM_SEL ?
+                                        "PCH only" : "the CPU, PCH and DIMMs");
+       msg_pdbg2("GPIO29 is used as %s.\n", s->cougar.SLP_LAN_GP29_SEL ?
+                 "general purpose output" : "SLP_LAN#");
+
+       /* PCHSTRP16 */
+       /* PCHSTRP17 */
+       msg_pdbg2("Integrated Clock: %s Clock Mode\n",
+                 s->cougar.ICML ? "Buffered Through" : "Full Integrated");
+       msg_pdbg2("\n");
+}
+
+void prettyprint_ich_descriptor_straps(enum ich_chipset cs, const struct ich_descriptors *desc)
+{
+       unsigned int i, max;
+       msg_pdbg2("=== Softstraps ===\n");
+
+       if (sizeof(desc->north.STRPs) / 4 + 1 < desc->content.MSL) {
+               max = sizeof(desc->north.STRPs) / 4 + 1;
+               msg_pdbg2("MSL (%u) is greater than the current maximum of %u "
+                         "entries.\n", desc->content.MSL, max + 1);
+               msg_pdbg2("Only the first %u entries will be printed.\n", max);
+       } else
+               max = desc->content.MSL;
+
+       msg_pdbg2("--- North/MCH/PROC (%d entries) ---\n", max);
+       for (i = 0; i < max; i++)
+               msg_pdbg2("STRP%-2d = 0x%08x\n", i, desc->north.STRPs[i]);
+       msg_pdbg2("\n");
+
+       if (sizeof(desc->south.STRPs) / 4 < desc->content.ISL) {
+               max = sizeof(desc->south.STRPs) / 4;
+               msg_pdbg2("ISL (%u) is greater than the current maximum of %u "
+                         "entries.\n", desc->content.ISL, max);
+               msg_pdbg2("Only the first %u entries will be printed.\n", max);
+       } else
+               max = desc->content.ISL;
+
+       msg_pdbg2("--- South/ICH/PCH (%d entries) ---\n", max);
+       for (i = 0; i < max; i++)
+               msg_pdbg2("STRP%-2d = 0x%08x\n", i, desc->south.STRPs[i]);
+       msg_pdbg2("\n");
+
+       switch (cs) {
+       case CHIPSET_ICH8:
+               if (sizeof(desc->north.ich8) / 4 != desc->content.MSL)
+                       msg_pdbg2("Detailed North/MCH/PROC information is "
+                                 "probably not reliable, printing anyway.\n");
+               if (sizeof(desc->south.ich8) / 4 != desc->content.ISL)
+                       msg_pdbg2("Detailed South/ICH/PCH information is "
+                                 "probably not reliable, printing anyway.\n");
+               prettyprint_ich_descriptor_straps_ich8(desc);
+               break;
+       case CHIPSET_5_SERIES_IBEX_PEAK:
+               /* PCH straps only. PROCSTRPs are unknown. */
+               if (sizeof(desc->south.ibex) / 4 != desc->content.ISL)
+                       msg_pdbg2("Detailed South/ICH/PCH information is "
+                                 "probably not reliable, printing anyway.\n");
+               prettyprint_ich_descriptor_straps_ibex(&desc->south);
+               break;
+       case CHIPSET_6_SERIES_COUGAR_POINT:
+               /* PCH straps only. PROCSTRP0 is "reserved". */
+               if (sizeof(desc->south.cougar) / 4 != desc->content.ISL)
+                       msg_pdbg2("Detailed South/ICH/PCH information is "
+                                 "probably not reliable, printing anyway.\n");
+               prettyprint_ich_descriptor_straps_cougar(&desc->south);
+               break;
+       case CHIPSET_ICH_UNKNOWN:
+               break;
+       default:
+               msg_pdbg2("The meaning of the descriptor straps are unknown "
+                         "yet.\n\n");
+               break;
+       }
+}
+
+void prettyprint_rdid(uint32_t reg_val)
+{
+       uint8_t mid = reg_val & 0xFF;
+       uint16_t did = ((reg_val >> 16) & 0xFF) | (reg_val & 0xFF00);
+       msg_pdbg2("Manufacturer ID 0x%02x, Device ID 0x%04x\n", mid, did);
+}
+
+void prettyprint_ich_descriptor_upper_map(const struct ich_desc_upper_map *umap)
+{
+       int i;
+       msg_pdbg2("=== Upper Map Section ===\n");
+       msg_pdbg2("FLUMAP1  0x%08x\n", umap->FLUMAP1);
+       msg_pdbg2("\n");
+
+       msg_pdbg2("--- Details ---\n");
+       msg_pdbg2("VTL (length in DWORDS) = %d\n", umap->VTL);
+       msg_pdbg2("VTBA (base address)    = 0x%6.6x\n", getVTBA(umap));
+       msg_pdbg2("\n");
+
+       msg_pdbg2("VSCC Table: %d entries\n", umap->VTL/2);
+       for (i = 0; i < umap->VTL/2; i++)
+       {
+               uint32_t jid = umap->vscc_table[i].JID;
+               uint32_t vscc = umap->vscc_table[i].VSCC;
+               msg_pdbg2("  JID%d  = 0x%08x\n", i, jid);
+               msg_pdbg2("  VSCC%d = 0x%08x\n", i, vscc);
+               msg_pdbg2("    "); /* indention */
+               prettyprint_rdid(jid);
+               msg_pdbg2("    "); /* indention */
+               prettyprint_ich_reg_vscc(vscc, 0);
+       }
+       msg_pdbg2("\n");
+}
+
+/* len is the length of dump in bytes */
+int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struct ich_descriptors *desc)
+{
+       unsigned int i, max;
+       uint8_t pch_bug_offset = 0;
+
+       if (dump == NULL || desc == NULL)
+               return ICH_RET_PARAM;
+
+       if (dump[0] != DESCRIPTOR_MODE_SIGNATURE) {
+               if (dump[4] == DESCRIPTOR_MODE_SIGNATURE)
+                       pch_bug_offset = 4;
+               else
+                       return ICH_RET_ERR;
+       }
+
+       /* map */
+       if (len < (4 + pch_bug_offset) * 4 - 1)
+               return ICH_RET_OOB;
+       desc->content.FLVALSIG  = dump[0 + pch_bug_offset];
+       desc->content.FLMAP0    = dump[1 + pch_bug_offset];
+       desc->content.FLMAP1    = dump[2 + pch_bug_offset];
+       desc->content.FLMAP2    = dump[3 + pch_bug_offset];
+
+       /* component */
+       if (len < (getFCBA(&desc->content) + 3 * 4 - 1))
+               return ICH_RET_OOB;
+       desc->component.FLCOMP  = dump[(getFCBA(&desc->content) >> 2) + 0];
+       desc->component.FLILL   = dump[(getFCBA(&desc->content) >> 2) + 1];
+       desc->component.FLPB    = dump[(getFCBA(&desc->content) >> 2) + 2];
+
+       /* region */
+       if (len < (getFRBA(&desc->content) + 5 * 4 - 1))
+               return ICH_RET_OOB;
+       desc->region.FLREGs[0] = dump[(getFRBA(&desc->content) >> 2) + 0];
+       desc->region.FLREGs[1] = dump[(getFRBA(&desc->content) >> 2) + 1];
+       desc->region.FLREGs[2] = dump[(getFRBA(&desc->content) >> 2) + 2];
+       desc->region.FLREGs[3] = dump[(getFRBA(&desc->content) >> 2) + 3];
+       desc->region.FLREGs[4] = dump[(getFRBA(&desc->content) >> 2) + 4];
+
+       /* master */
+       if (len < (getFMBA(&desc->content) + 3 * 4 - 1))
+               return ICH_RET_OOB;
+       desc->master.FLMSTR1 = dump[(getFMBA(&desc->content) >> 2) + 0];
+       desc->master.FLMSTR2 = dump[(getFMBA(&desc->content) >> 2) + 1];
+       desc->master.FLMSTR3 = dump[(getFMBA(&desc->content) >> 2) + 2];
+
+       /* upper map */
+       desc->upper.FLUMAP1 = dump[(UPPER_MAP_OFFSET >> 2) + 0];
+
+       /* VTL is 8 bits long. Quote from the Ibex Peak SPI programming guide:
+        * "Identifies the 1s based number of DWORDS contained in the VSCC
+        * Table. Each SPI component entry in the table is 2 DWORDS long." So
+        * the maximum of 255 gives us 127.5 SPI components(!?) 8 bytes each. A
+        * check ensures that the maximum offset actually accessed is available.
+        */
+       if (len < (getVTBA(&desc->upper) + (desc->upper.VTL / 2 * 8) - 1))
+               return ICH_RET_OOB;
+
+       for (i = 0; i < desc->upper.VTL/2; i++) {
+               desc->upper.vscc_table[i].JID  =
+                                dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 0];
+               desc->upper.vscc_table[i].VSCC =
+                                dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 1];
+       }
+
+       /* MCH/PROC (aka. North) straps */
+       if (len < getFMSBA(&desc->content) + desc->content.MSL * 4)
+               return ICH_RET_OOB;
+
+       /* limit the range to be written */
+       max = min(sizeof(desc->north.STRPs) / 4, desc->content.MSL);
+       for (i = 0; i < max; i++)
+                       desc->north.STRPs[i] =
+                                     dump[(getFMSBA(&desc->content) >> 2) + i];
+
+       /* ICH/PCH (aka. South) straps */
+       if (len < getFISBA(&desc->content) + desc->content.ISL * 4)
+               return ICH_RET_OOB;
+
+       /* limit the range to be written */
+       max = min(sizeof(desc->south.STRPs) / 4, desc->content.ISL);
+       for (i = 0; i < max; i++)
+                       desc->south.STRPs[i] =
+                                     dump[(getFISBA(&desc->content) >> 2) + i];
+
+       return ICH_RET_OK;
+}
+
+#else /* ICH_DESCRIPTORS_FROM_DUMP */
+
+/** Returns the integer representation of the component density with index
+idx in bytes or 0 if a correct size can not be determined. */
+int getFCBA_component_density(const struct ich_descriptors *desc, uint8_t idx)
+{
+       uint8_t size_enc;
+       
+       switch(idx) {
+       case 0:
+               size_enc = desc->component.comp1_density;
+               break;
+       case 1:
+               if (desc->content.NC == 0)
+                       return 0;
+               size_enc = desc->component.comp2_density;
+               break;
+       default:
+               msg_perr("Only ICH SPI component index 0 or 1 are supported "
+                        "yet.\n");
+               return 0;
+       }
+       if (size_enc > 5) {
+               msg_perr("Density of ICH SPI component with index %d is "
+                        "invalid. Encoded density is 0x%x.\n", idx, size_enc);
+               return 0;
+       }
+       return (1 << (19 + size_enc));
+}
+
+static uint32_t read_descriptor_reg(uint8_t section, uint16_t offset, void *spibar)
+{
+       uint32_t control = 0;
+       control |= (section << FDOC_FDSS_OFF) & FDOC_FDSS;
+       control |= (offset << FDOC_FDSI_OFF) & FDOC_FDSI;
+       mmio_le_writel(control, spibar + ICH9_REG_FDOC);
+       return mmio_le_readl(spibar + ICH9_REG_FDOD);
+}
+
+int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc)
+{
+       uint8_t i;
+       uint8_t nr;
+       struct ich_desc_region *r = &desc->region;
+
+       /* Test if bit-fields are working as expected.
+        * FIXME: Replace this with dynamic bitfield fixup
+        */
+       for (i = 0; i < 4; i++)
+               desc->region.FLREGs[i] = 0x5A << (i * 8);
+       if (r->reg0_base != 0x005A || r->reg0_limit != 0x0000 ||
+           r->reg1_base != 0x1A00 || r->reg1_limit != 0x0000 ||
+           r->reg2_base != 0x0000 || r->reg2_limit != 0x005A ||
+           r->reg3_base != 0x0000 || r->reg3_limit != 0x1A00) {
+               msg_pdbg("The combination of compiler and CPU architecture used"
+                        "does not lay out bit-fields as expected, sorry.\n");
+               msg_pspew("r->reg0_base  = 0x%04X (0x005A)\n", r->reg0_base);
+               msg_pspew("r->reg0_limit = 0x%04X (0x0000)\n", r->reg0_limit);
+               msg_pspew("r->reg1_base  = 0x%04X (0x1A00)\n", r->reg1_base);
+               msg_pspew("r->reg1_limit = 0x%04X (0x0000)\n", r->reg1_limit);
+               msg_pspew("r->reg2_base  = 0x%04X (0x0000)\n", r->reg2_base);
+               msg_pspew("r->reg2_limit = 0x%04X (0x005A)\n", r->reg2_limit);
+               msg_pspew("r->reg3_base  = 0x%04X (0x0000)\n", r->reg3_base);
+               msg_pspew("r->reg3_limit = 0x%04X (0x1A00)\n", r->reg3_limit);
+               return ICH_RET_ERR;
+       }
+
+       msg_pdbg2("Reading flash descriptors "
+                "mapped by the chipset via FDOC/FDOD...");
+       /* content section */
+       desc->content.FLVALSIG  = read_descriptor_reg(0, 0, spibar);
+       desc->content.FLMAP0    = read_descriptor_reg(0, 1, spibar);
+       desc->content.FLMAP1    = read_descriptor_reg(0, 2, spibar);
+       desc->content.FLMAP2    = read_descriptor_reg(0, 3, spibar);
+
+       /* component section */
+       desc->component.FLCOMP  = read_descriptor_reg(1, 0, spibar);
+       desc->component.FLILL   = read_descriptor_reg(1, 1, spibar);
+       desc->component.FLPB    = read_descriptor_reg(1, 2, spibar);
+
+       /* region section */
+       nr = desc->content.NR + 1;
+       if (nr > 5) {
+               msg_pdbg2("%s: number of regions too high (%d) - failed\n",
+                         __func__, nr);
+               return ICH_RET_ERR;
+       }
+       for (i = 0; i <= nr; i++)
+               desc->region.FLREGs[i] = read_descriptor_reg(2, i, spibar);
+
+       /* master section */
+       desc->master.FLMSTR1 = read_descriptor_reg(3, 0, spibar);
+       desc->master.FLMSTR2 = read_descriptor_reg(3, 1, spibar);
+       desc->master.FLMSTR3 = read_descriptor_reg(3, 2, spibar);
+
+       /* Accessing the strap section via FDOC/D is only possible on ICH8 and
+        * reading the upper map is impossible on all chipsets, so don't bother.
+        */
+
+       msg_pdbg2(" done.\n");
+       return ICH_RET_OK;
+}
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/ich_descriptors.h b/ich_descriptors.h
new file mode 100644 (file)
index 0000000..3a44740
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (c) 2010  Matthias Wenzel <bios at mazzoo dot de>
+ * Copyright (c) 2011  Stefan Tauner
+ *
+ * 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
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+#ifndef __ICH_DESCRIPTORS_H__
+#define __ICH_DESCRIPTORS_H__ 1
+
+#include <stdint.h>
+#include "programmer.h" /* for enum ich_chipset */
+
+/* FIXME: Replace with generic return codes */
+#define ICH_RET_OK     0
+#define ICH_RET_ERR    -1
+#define ICH_RET_WARN   -2
+#define ICH_RET_PARAM  -3
+#define ICH_RET_OOB    -4
+
+#define ICH9_REG_FDOC          0xB0    /* 32 Bits Flash Descriptor Observability Control */
+                                       /* 0-1: reserved */
+#define FDOC_FDSI_OFF          2       /* 2-11: Flash Descriptor Section Index */
+#define FDOC_FDSI              (0x3f << FDOC_FDSI_OFF)
+#define FDOC_FDSS_OFF          12      /* 12-14: Flash Descriptor Section Select */
+#define FDOC_FDSS              (0x3 << FDOC_FDSS_OFF)
+                                       /* 15-31: reserved */
+
+#define ICH9_REG_FDOD          0xB4    /* 32 Bits Flash Descriptor Observability Data */
+
+/* Field locations and semantics for LVSCC, UVSCC and related words in the flash
+ * descriptor are equal therefore they all share the same macros below. */
+#define VSCC_BES_OFF           0       /* 0-1: Block/Sector Erase Size */
+#define VSCC_BES                       (0x3 << VSCC_BES_OFF)
+#define VSCC_WG_OFF            2       /* 2: Write Granularity */
+#define VSCC_WG                                (0x1 << VSCC_WG_OFF)
+#define VSCC_WSR_OFF           3       /* 3: Write Status Required */
+#define VSCC_WSR                       (0x1 << VSCC_WSR_OFF)
+#define VSCC_WEWS_OFF          4       /* 4: Write Enable on Write Status */
+#define VSCC_WEWS                      (0x1 << VSCC_WEWS_OFF)
+                                       /* 5-7: reserved */
+#define VSCC_EO_OFF            8       /* 8-15: Erase Opcode */
+#define VSCC_EO                                (0xff << VSCC_EO_OFF)
+                                       /* 16-22: reserved */
+#define VSCC_VCL_OFF           23      /* 23: Vendor Component Lock */
+#define VSCC_VCL                       (0x1 << VSCC_VCL_OFF)
+                                       /* 24-31: reserved */
+
+#define ICH_FREG_BASE(flreg)  (((flreg) << 12) & 0x01fff000)
+#define ICH_FREG_LIMIT(flreg) (((flreg) >>  4) & 0x01fff000)
+
+void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity);
+
+struct ich_desc_content {
+       uint32_t FLVALSIG;      /* 0x00 */
+       union {                 /* 0x04 */
+               uint32_t FLMAP0;
+               struct {
+                       uint32_t FCBA   :8, /* Flash Component Base Address */
+                                NC     :2, /* Number Of Components */
+                                       :6,
+                                FRBA   :8, /* Flash Region Base Address */
+                                NR     :3, /* Number Of Regions */
+                                       :5;
+               };
+       };
+       union {                 /* 0x08 */
+               uint32_t FLMAP1;
+               struct {
+                       uint32_t FMBA   :8, /* Flash Master Base Address */
+                                NM     :3, /* Number Of Masters */
+                                       :5,
+                                FISBA  :8, /* Flash ICH Strap Base Address */
+                                ISL    :8; /* ICH Strap Length */
+               };
+       };
+       union {                 /* 0x0c */
+               uint32_t FLMAP2;
+               struct {
+                       uint32_t FMSBA  :8, /* Flash (G)MCH Strap Base Addr. */
+                                MSL    :8, /* MCH Strap Length */
+                                       :16;
+               };
+       };
+};
+
+struct ich_desc_component {
+       union {                 /* 0x00 */
+               uint32_t FLCOMP; /* Flash Components Register */
+               struct {
+                       uint32_t comp1_density  :3,
+                                comp2_density  :3,
+                                               :11,
+                                freq_read      :3,
+                                fastread       :1,
+                                freq_fastread  :3,
+                                freq_write     :3,
+                                freq_read_id   :3,
+                                               :2;
+               };
+       };
+       union {                 /* 0x04 */
+               uint32_t FLILL; /* Flash Invalid Instructions Register */
+               struct {
+                       uint32_t invalid_instr0 :8,
+                                invalid_instr1 :8,
+                                invalid_instr2 :8,
+                                invalid_instr3 :8;
+               };
+       };
+       union {                 /* 0x08 */
+               uint32_t FLPB; /* Flash Partition Boundary Register */
+               struct {
+                       uint32_t FPBA   :13, /* Flash Partition Boundary Addr */
+                                       :19;
+               };
+       };
+};
+
+struct ich_desc_region {
+       union {
+               uint32_t FLREGs[5];
+               struct {
+                       struct { /* FLREG0 Flash Descriptor */
+                               uint32_t reg0_base      :13,
+                                                       :3,
+                                        reg0_limit     :13,
+                                                       :3;
+                       };
+                       struct { /* FLREG1 BIOS */
+                               uint32_t reg1_base      :13,
+                                                       :3,
+                                        reg1_limit     :13,
+                                                       :3;
+                       };
+                       struct { /* FLREG2 ME */
+                               uint32_t reg2_base      :13,
+                                                       :3,
+                                        reg2_limit     :13,
+                                                       :3;
+                       };
+                       struct { /* FLREG3 GbE */
+                               uint32_t reg3_base      :13,
+                                                       :3,
+                                        reg3_limit     :13,
+                                                       :3;
+                       };
+                       struct { /* FLREG4 Platform */
+                               uint32_t reg4_base      :13,
+                                                       :3,
+                                        reg4_limit     :13,
+                                                       :3;
+                       };
+               };
+       };
+};
+
+struct ich_desc_master {
+       union {
+               uint32_t FLMSTR1;
+               struct {
+                       uint32_t BIOS_req_ID    :16,
+                                BIOS_descr_r   :1,
+                                BIOS_BIOS_r    :1,
+                                BIOS_ME_r      :1,
+                                BIOS_GbE_r     :1,
+                                BIOS_plat_r    :1,
+                                               :3,
+                                BIOS_descr_w   :1,
+                                BIOS_BIOS_w    :1,
+                                BIOS_ME_w      :1,
+                                BIOS_GbE_w     :1,
+                                BIOS_plat_w    :1,
+                                               :3;
+               };
+       };
+       union {
+               uint32_t FLMSTR2;
+               struct {
+                       uint32_t ME_req_ID      :16,
+                                ME_descr_r     :1,
+                                ME_BIOS_r      :1,
+                                ME_ME_r        :1,
+                                ME_GbE_r       :1,
+                                ME_plat_r      :1,
+                                               :3,
+                                ME_descr_w     :1,
+                                ME_BIOS_w      :1,
+                                ME_ME_w        :1,
+                                ME_GbE_w       :1,
+                                ME_plat_w      :1,
+                                               :3;
+               };
+       };
+       union {
+               uint32_t FLMSTR3;
+               struct {
+                       uint32_t GbE_req_ID     :16,
+                                GbE_descr_r    :1,
+                                GbE_BIOS_r     :1,
+                                GbE_ME_r       :1,
+                                GbE_GbE_r      :1,
+                                GbE_plat_r     :1,
+                                               :3,
+                                GbE_descr_w    :1,
+                                GbE_BIOS_w     :1,
+                                GbE_ME_w       :1,
+                                GbE_GbE_w      :1,
+                                GbE_plat_w     :1,
+                                               :3;
+               };
+       };
+};
+
+#ifdef ICH_DESCRIPTORS_FROM_DUMP
+struct ich_desc_north_strap {
+       union {
+               uint32_t STRPs[1]; /* current maximum: ich8 */
+               struct { /* ich8 */
+                       struct { /* STRP2 (in the datasheet) */
+                               uint32_t MDB                    :1,
+                                                               :31;
+                       };
+               } ich8;
+       };
+};
+
+struct ich_desc_south_strap {
+       union {
+               uint32_t STRPs[18]; /* current maximum: cougar point */
+               struct { /* ich8 */
+                       struct { /* STRP1 */
+                               uint32_t ME_DISABLE             :1,
+                                                               :6,
+                                        TCOMODE                :1,
+                                        ASD                    :7,
+                                        BMCMODE                :1,
+                                                               :3,
+                                        GLAN_PCIE_SEL          :1,
+                                        GPIO12_SEL             :2,
+                                        SPICS1_LANPHYPC_SEL    :1,
+                                        MESM2SEL               :1,
+                                                               :1,
+                                        ASD2                   :7;
+                       };
+               } ich8;
+               struct { /* ibex peak */
+                       struct { /* STRP0 */
+                               uint32_t                        :1,
+                                        cs_ss2                 :1,
+                                                               :5,
+                                        SMB_EN                 :1,
+                                        SML0_EN                :1,
+                                        SML1_EN                :1,
+                                        SML1FRQ                :2,
+                                        SMB0FRQ                :2,
+                                        SML0FRQ                :2,
+                                                               :4,
+                                        LANPHYPC_GP12_SEL      :1,
+                                        cs_ss1                 :1,
+                                                               :2,
+                                        DMI_REQID_DIS          :1,
+                                                               :4,
+                                        BBBS                   :2,
+                                                               :1;
+                       };
+                       struct { /* STRP1 */
+                               uint32_t cs_ss3                 :4,
+                                                               :28;
+                       };
+                       struct { /* STRP2 */
+                               uint32_t                        :8,
+                                        MESMASDEN              :1,
+                                        MESMASDA               :7,
+                                                               :8,
+                                        MESMI2CEN              :1,
+                                        MESMI2CA               :7;
+                       };
+                       struct { /* STRP3 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP4 */
+                               uint32_t PHYCON                 :2,
+                                                               :6,
+                                        GBEMAC_SMBUS_ADDR_EN   :1,
+                                        GBEMAC_SMBUS_ADDR      :7,
+                                                               :1,
+                                        GBEPHY_SMBUS_ADDR      :7,
+                                                               :8;
+                       };
+                       struct { /* STRP5 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP6 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP7 */
+                               uint32_t MESMA2UDID_VENDOR      :16,
+                                        MESMA2UDID_DEVICE      :16;
+                       };
+                       struct { /* STRP8 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP9 */
+                               uint32_t PCIEPCS1               :2,
+                                        PCIEPCS2               :2,
+                                        PCIELR1                :1,
+                                        PCIELR2                :1,
+                                        DMILR                  :1,
+                                                               :1,
+                                        PHY_PCIEPORTSEL        :3,
+                                        PHY_PCIE_EN            :1,
+                                                               :20;
+                       };
+                       struct { /* STRP10 */
+                               uint32_t                        :1,
+                                        ME_BOOT_FLASH          :1,
+                                        cs_ss5                 :1,
+                                        VE_EN                  :1,
+                                                               :4,
+                                        MMDDE                  :1,
+                                        MMADDR                 :7,
+                                        cs_ss7                 :1,
+                                                               :1,
+                                        ICC_SEL                :3,
+                                        MER_CL1                :1,
+                                                               :10;
+                       };
+                       struct { /* STRP11 */
+                               uint32_t SML1GPAEN              :1,
+                                        SML1GPA                :7,
+                                                               :16,
+                                        SML1I2CAEN             :1,
+                                        SML1I2CA               :7;
+                       };
+                       struct { /* STRP12 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP13 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP14 */
+                               uint32_t                        :8,
+                                        VE_EN2                 :1,
+                                                               :5,
+                                        VE_BOOT_FLASH          :1,
+                                                               :1,
+                                        BW_SSD                 :1,
+                                        NVMHCI_EN              :1,
+                                                               :14;
+                       };
+                       struct { /* STRP15 */
+                               uint32_t                        :3,
+                                        cs_ss6                 :2,
+                                                               :1,
+                                        IWL_EN                 :1,
+                                                               :1,
+                                        t209min                :2,
+                                                               :22;
+                       };
+               } ibex;
+               struct { /* cougar point */
+                       struct { /* STRP0 */
+                               uint32_t                        :1,
+                                        cs_ss1                 :1,
+                                                               :5,
+                                        SMB_EN                 :1,
+                                        SML0_EN                :1,
+                                        SML1_EN                :1,
+                                        SML1FRQ                :2,
+                                        SMB0FRQ                :2,
+                                        SML0FRQ                :2,
+                                                               :4,
+                                        LANPHYPC_GP12_SEL      :1,
+                                        LINKSEC_DIS            :1,
+                                                               :2,
+                                        DMI_REQID_DIS          :1,
+                                                               :4,
+                                        BBBS                   :2,
+                                                               :1;
+                       };
+                       struct { /* STRP1 */
+                               uint32_t cs_ss3                 :4,
+                                                               :4,
+                                        cs_ss2                 :1,
+                                                               :28;
+                       };
+                       struct { /* STRP2 */
+                               uint32_t                        :8,
+                                        MESMASDEN              :1,
+                                        MESMASDA               :7,
+                                        MESMMCTPAEN            :1,
+                                        MESMMCTPA              :7,
+                                        MESMI2CEN              :1,
+                                        MESMI2CA               :7;
+                       };
+                       struct { /* STRP3 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP4 */
+                               uint32_t PHYCON                 :2,
+                                                               :6,
+                                        GBEMAC_SMBUS_ADDR_EN   :1,
+                                        GBEMAC_SMBUS_ADDR      :7,
+                                                               :1,
+                                        GBEPHY_SMBUS_ADDR      :7,
+                                                               :8;
+                       };
+                       struct { /* STRP5 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP6 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP7 */
+                               uint32_t MESMA2UDID_VENDOR      :16,
+                                        MESMA2UDID_DEVICE      :16;
+                       };
+                       struct { /* STRP8 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP9 */
+                               uint32_t PCIEPCS1               :2,
+                                        PCIEPCS2               :2,
+                                        PCIELR1                :1,
+                                        PCIELR2                :1,
+                                        DMILR                  :1,
+                                        cs_ss4                 :1,
+                                        PHY_PCIEPORTSEL        :3,
+                                        PHY_PCIE_EN            :1,
+                                                               :2,
+                                        SUB_DECODE_EN          :1,
+                                                               :7,
+                                        PCHHOT_SML1ALERT_SEL   :1,
+                                                               :9;
+                       };
+                       struct { /* STRP10 */
+                               uint32_t                        :1,
+                                        ME_BOOT_FLASH          :1,
+                                                               :6,
+                                        MDSMBE_EN              :1,
+                                        MDSMBE_ADD             :7,
+                                                               :2,
+                                        ICC_SEL                :3,
+                                        MER_CL1                :1,
+                                        ICC_PRO_SEL            :1,
+                                        Deep_SX_EN             :1,
+                                        ME_DBG_LAN             :1,
+                                                               :7;
+                       };
+                       struct { /* STRP11 */
+                               uint32_t SML1GPAEN              :1,
+                                        SML1GPA                :7,
+                                                               :16,
+                                        SML1I2CAEN             :1,
+                                        SML1I2CA               :7;
+                       };
+                       struct { /* STRP12 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP13 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP14 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP15 */
+                               uint32_t cs_ss6                 :6,
+                                        IWL_EN                 :1,
+                                        cs_ss5                 :2,
+                                                               :4,
+                                        SMLINK1_THERM_SEL      :1,
+                                        SLP_LAN_GP29_SEL       :1,
+                                                               :16;
+                       };
+                       struct { /* STRP16 */
+                               uint32_t                        :32;
+                       };
+                       struct { /* STRP17 */
+                               uint32_t ICML                   :1,
+                                        cs_ss7                 :1,
+                                                               :30;
+                       };
+               } cougar;
+       };
+};
+
+struct ich_desc_upper_map {
+       union {
+               uint32_t FLUMAP1;               /* Flash Upper Map 1 */
+               struct {
+                       uint32_t VTBA   :8,     /* ME VSCC Table Base Address */
+                                VTL    :8,     /* ME VSCC Table Length */
+                                       :16;
+               };
+       };
+       struct {
+               union {         /* JEDEC-ID Register */
+                       uint32_t JID;
+                       struct {
+                               uint32_t vid    :8, /* Vendor ID */
+                                        cid0   :8, /* Component ID 0 */
+                                        cid1   :8, /* Component ID 1 */
+                                               :8;
+                       };
+               };
+               union {         /* Vendor Specific Component Capabilities */
+                       uint32_t VSCC;
+                       struct {
+                               uint32_t ubes   :2, /* Upper Block/Sector Erase Size */
+                                        uwg    :1, /* Upper Write Granularity */
+                                        uwsr   :1, /* Upper Write Status Required */
+                                        uwews  :1, /* Upper Write Enable on Write Status */
+                                               :3,
+                                        ueo    :8, /* Upper Erase Opcode */
+                                        lbes   :2, /* Lower Block/Sector Erase Size */
+                                        lwg    :1, /* Lower Write Granularity */
+                                        lwsr   :1, /* Lower Write Status Required */
+                                        lwews  :1, /* Lower Write Enable on Write Status */
+                                               :3,
+                                        leo    :16; /* Lower Erase Opcode */
+                       };
+               };
+       } vscc_table[128];
+};
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */
+
+struct ich_descriptors {
+       struct ich_desc_content content;
+       struct ich_desc_component component;
+       struct ich_desc_region region;
+       struct ich_desc_master master;
+#ifdef ICH_DESCRIPTORS_FROM_DUMP
+       struct ich_desc_north_strap north;
+       struct ich_desc_south_strap south;
+       struct ich_desc_upper_map upper;
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */
+};
+
+void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descriptors *desc);
+
+void prettyprint_ich_descriptor_content(const struct ich_desc_content *content);
+void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc);
+void prettyprint_ich_descriptor_region(const struct ich_descriptors *desc);
+void prettyprint_ich_descriptor_master(const struct ich_desc_master *master);
+
+#ifdef ICH_DESCRIPTORS_FROM_DUMP
+
+void prettyprint_ich_descriptor_upper_map(const struct ich_desc_upper_map *umap);
+void prettyprint_ich_descriptor_straps(enum ich_chipset cs, const struct ich_descriptors *desc);
+int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struct ich_descriptors *desc);
+
+#else /* ICH_DESCRIPTORS_FROM_DUMP */
+
+int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc);
+int getFCBA_component_density(const struct ich_descriptors *desc, uint8_t idx);
+
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */
+#endif /* __ICH_DESCRIPTORS_H__ */
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/ichspi.c b/ichspi.c
new file mode 100644 (file)
index 0000000..0223ae3
--- /dev/null
+++ b/ichspi.c
@@ -0,0 +1,1897 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Stefan Wildemann <stefan.wildemann@kontron.com>
+ * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.com>
+ * Copyright (C) 2008 Dominik Geyer <dominik.geyer@kontron.com>
+ * Copyright (C) 2008 coresystems GmbH <info@coresystems.de>
+ * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2011 Stefan Tauner
+ *
+ * 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
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <string.h>
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+#include "spi.h"
+#include "ich_descriptors.h"
+
+/* ICH9 controller register definition */
+#define ICH9_REG_HSFS          0x04    /* 16 Bits Hardware Sequencing Flash Status */
+#define HSFS_FDONE_OFF         0       /* 0: Flash Cycle Done */
+#define HSFS_FDONE             (0x1 << HSFS_FDONE_OFF)
+#define HSFS_FCERR_OFF         1       /* 1: Flash Cycle Error */
+#define HSFS_FCERR             (0x1 << HSFS_FCERR_OFF)
+#define HSFS_AEL_OFF           2       /* 2: Access Error Log */
+#define HSFS_AEL               (0x1 << HSFS_AEL_OFF)
+#define HSFS_BERASE_OFF                3       /* 3-4: Block/Sector Erase Size */
+#define HSFS_BERASE            (0x3 << HSFS_BERASE_OFF)
+#define HSFS_SCIP_OFF          5       /* 5: SPI Cycle In Progress */
+#define HSFS_SCIP              (0x1 << HSFS_SCIP_OFF)
+                                       /* 6-12: reserved */
+#define HSFS_FDOPSS_OFF                13      /* 13: Flash Descriptor Override Pin-Strap Status */
+#define HSFS_FDOPSS            (0x1 << HSFS_FDOPSS_OFF)
+#define HSFS_FDV_OFF           14      /* 14: Flash Descriptor Valid */
+#define HSFS_FDV               (0x1 << HSFS_FDV_OFF)
+#define HSFS_FLOCKDN_OFF       15      /* 15: Flash Configuration Lock-Down */
+#define HSFS_FLOCKDN           (0x1 << HSFS_FLOCKDN_OFF)
+
+#define ICH9_REG_HSFC          0x06    /* 16 Bits Hardware Sequencing Flash Control */
+#define HSFC_FGO_OFF           0       /* 0: Flash Cycle Go */
+#define HSFC_FGO               (0x1 << HSFC_FGO_OFF)
+#define HSFC_FCYCLE_OFF                1       /* 1-2: FLASH Cycle */
+#define HSFC_FCYCLE            (0x3 << HSFC_FCYCLE_OFF)
+                                       /* 3-7: reserved */
+#define HSFC_FDBC_OFF          8       /* 8-13: Flash Data Byte Count */
+#define HSFC_FDBC              (0x3f << HSFC_FDBC_OFF)
+                                       /* 14: reserved */
+#define HSFC_SME_OFF           15      /* 15: SPI SMI# Enable */
+#define HSFC_SME               (0x1 << HSFC_SME_OFF)
+
+#define ICH9_REG_FADDR         0x08    /* 32 Bits */
+#define ICH9_REG_FDATA0                0x10    /* 64 Bytes */
+
+#define ICH9_REG_FRAP          0x50    /* 32 Bytes Flash Region Access Permissions */
+#define ICH9_REG_FREG0         0x54    /* 32 Bytes Flash Region 0 */
+
+#define ICH9_REG_PR0           0x74    /* 32 Bytes Protected Range 0 */
+#define PR_WP_OFF              31      /* 31: write protection enable */
+#define PR_RP_OFF              15      /* 15: read protection enable */
+
+#define ICH9_REG_SSFS          0x90    /* 08 Bits */
+#define SSFS_SCIP_OFF          0       /* SPI Cycle In Progress */
+#define SSFS_SCIP              (0x1 << SSFS_SCIP_OFF)
+#define SSFS_FDONE_OFF         2       /* Cycle Done Status */
+#define SSFS_FDONE             (0x1 << SSFS_FDONE_OFF)
+#define SSFS_FCERR_OFF         3       /* Flash Cycle Error */
+#define SSFS_FCERR             (0x1 << SSFS_FCERR_OFF)
+#define SSFS_AEL_OFF           4       /* Access Error Log */
+#define SSFS_AEL               (0x1 << SSFS_AEL_OFF)
+/* The following bits are reserved in SSFS: 1,5-7. */
+#define SSFS_RESERVED_MASK     0x000000e2
+
+#define ICH9_REG_SSFC          0x91    /* 24 Bits */
+/* We combine SSFS and SSFC to one 32-bit word,
+ * therefore SSFC bits are off by 8. */
+                                               /* 0: reserved */
+#define SSFC_SCGO_OFF          (1 + 8)         /* 1: SPI Cycle Go */
+#define SSFC_SCGO              (0x1 << SSFC_SCGO_OFF)
+#define SSFC_ACS_OFF           (2 + 8)         /* 2: Atomic Cycle Sequence */
+#define SSFC_ACS               (0x1 << SSFC_ACS_OFF)
+#define SSFC_SPOP_OFF          (3 + 8)         /* 3: Sequence Prefix Opcode Pointer */
+#define SSFC_SPOP              (0x1 << SSFC_SPOP_OFF)
+#define SSFC_COP_OFF           (4 + 8)         /* 4-6: Cycle Opcode Pointer */
+#define SSFC_COP               (0x7 << SSFC_COP_OFF)
+                                               /* 7: reserved */
+#define SSFC_DBC_OFF           (8 + 8)         /* 8-13: Data Byte Count */
+#define SSFC_DBC               (0x3f << SSFC_DBC_OFF)
+#define SSFC_DS_OFF            (14 + 8)        /* 14: Data Cycle */
+#define SSFC_DS                        (0x1 << SSFC_DS_OFF)
+#define SSFC_SME_OFF           (15 + 8)        /* 15: SPI SMI# Enable */
+#define SSFC_SME               (0x1 << SSFC_SME_OFF)
+#define SSFC_SCF_OFF           (16 + 8)        /* 16-18: SPI Cycle Frequency */
+#define SSFC_SCF               (0x7 << SSFC_SCF_OFF)
+#define SSFC_SCF_20MHZ         0x00000000
+#define SSFC_SCF_33MHZ         0x01000000
+                                               /* 19-23: reserved */
+#define SSFC_RESERVED_MASK     0xf8008100
+
+#define ICH9_REG_PREOP         0x94    /* 16 Bits */
+#define ICH9_REG_OPTYPE                0x96    /* 16 Bits */
+#define ICH9_REG_OPMENU                0x98    /* 64 Bits */
+
+#define ICH9_REG_BBAR          0xA0    /* 32 Bits BIOS Base Address Configuration */
+#define BBAR_MASK      0x00ffff00              /* 8-23: Bottom of System Flash */
+
+#define ICH8_REG_VSCC          0xC1    /* 32 Bits Vendor Specific Component Capabilities */
+#define ICH9_REG_LVSCC         0xC4    /* 32 Bits Host Lower Vendor Specific Component Capabilities */
+#define ICH9_REG_UVSCC         0xC8    /* 32 Bits Host Upper Vendor Specific Component Capabilities */
+/* The individual fields of the VSCC registers are defined in the file
+ * ich_descriptors.h. The reason is that the same layout is also used in the
+ * flash descriptor to define the properties of the different flash chips
+ * supported. The BIOS (or the ME?) is responsible to populate the ICH registers
+ * with the information from the descriptor on startup depending on the actual
+ * chip(s) detected. */
+
+#define ICH9_REG_FPB           0xD0    /* 32 Bits Flash Partition Boundary */
+#define FPB_FPBA_OFF           0       /* 0-12: Block/Sector Erase Size */
+#define FPB_FPBA                       (0x1FFF << FPB_FPBA_OFF)
+
+// ICH9R SPI commands
+#define SPI_OPCODE_TYPE_READ_NO_ADDRESS                0
+#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS       1
+#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS      2
+#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS     3
+
+// ICH7 registers
+#define ICH7_REG_SPIS          0x00    /* 16 Bits */
+#define SPIS_SCIP              0x0001
+#define SPIS_GRANT             0x0002
+#define SPIS_CDS               0x0004
+#define SPIS_FCERR             0x0008
+#define SPIS_RESERVED_MASK     0x7ff0
+
+/* VIA SPI is compatible with ICH7, but maxdata
+   to transfer is 16 bytes.
+
+   DATA byte count on ICH7 is 8:13, on VIA 8:11
+
+   bit 12 is port select CS0 CS1
+   bit 13 is FAST READ enable
+   bit 7  is used with fast read and one shot controls CS de-assert?
+*/
+
+#define ICH7_REG_SPIC          0x02    /* 16 Bits */
+#define SPIC_SCGO              0x0002
+#define SPIC_ACS               0x0004
+#define SPIC_SPOP              0x0008
+#define SPIC_DS                        0x4000
+
+#define ICH7_REG_SPIA          0x04    /* 32 Bits */
+#define ICH7_REG_SPID0         0x08    /* 64 Bytes */
+#define ICH7_REG_PREOP         0x54    /* 16 Bits */
+#define ICH7_REG_OPTYPE                0x56    /* 16 Bits */
+#define ICH7_REG_OPMENU                0x58    /* 64 Bits */
+
+/* ICH SPI configuration lock-down. May be set during chipset enabling. */
+static int ichspi_lock = 0;
+
+static enum ich_chipset ich_generation = CHIPSET_ICH_UNKNOWN;
+uint32_t ichspi_bbar = 0;
+
+static void *ich_spibar = NULL;
+
+typedef struct _OPCODE {
+       uint8_t opcode;         //This commands spi opcode
+       uint8_t spi_type;       //This commands spi type
+       uint8_t atomic;         //Use preop: (0: none, 1: preop0, 2: preop1
+} OPCODE;
+
+/* Suggested opcode definition:
+ * Preop 1: Write Enable
+ * Preop 2: Write Status register enable
+ *
+ * OP 0: Write address
+ * OP 1: Read Address
+ * OP 2: ERASE block
+ * OP 3: Read Status register
+ * OP 4: Read ID
+ * OP 5: Write Status register
+ * OP 6: chip private (read JEDEC id)
+ * OP 7: Chip erase
+ */
+typedef struct _OPCODES {
+       uint8_t preop[2];
+       OPCODE opcode[8];
+} OPCODES;
+
+static OPCODES *curopcodes = NULL;
+
+/* HW access functions */
+static uint32_t REGREAD32(int X)
+{
+       return mmio_readl(ich_spibar + X);
+}
+
+static uint16_t REGREAD16(int X)
+{
+       return mmio_readw(ich_spibar + X);
+}
+
+static uint16_t REGREAD8(int X)
+{
+       return mmio_readb(ich_spibar + X);
+}
+
+#define REGWRITE32(off, val) mmio_writel(val, ich_spibar+(off))
+#define REGWRITE16(off, val) mmio_writew(val, ich_spibar+(off))
+#define REGWRITE8(off, val)  mmio_writeb(val, ich_spibar+(off))
+
+/* Common SPI functions */
+static int find_opcode(OPCODES *op, uint8_t opcode);
+static int find_preop(OPCODES *op, uint8_t preop);
+static int generate_opcodes(OPCODES * op);
+static int program_opcodes(OPCODES *op, int enable_undo);
+static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
+                     uint8_t datalength, uint8_t * data);
+
+/* for pairing opcodes with their required preop */
+struct preop_opcode_pair {
+       uint8_t preop;
+       uint8_t opcode;
+};
+
+/* List of opcodes which need preopcodes and matching preopcodes. Unused. */
+const struct preop_opcode_pair pops[] = {
+       {JEDEC_WREN, JEDEC_BYTE_PROGRAM},
+       {JEDEC_WREN, JEDEC_SE}, /* sector erase */
+       {JEDEC_WREN, JEDEC_BE_52}, /* block erase */
+       {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.
+ */
+static OPCODES O_ST_M25P = {
+       {
+        JEDEC_WREN,
+        JEDEC_EWSR,
+       },
+       {
+        {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, 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, 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, 0},    // Bulk erase
+       }
+};
+
+/* List of opcodes with their corresponding spi_type
+ * It is used to reprogram the chipset OPCODE table on-the-fly if an opcode
+ * is needed which is currently not in the chipset OPCODE table
+ */
+static OPCODE POSSIBLE_OPCODES[] = {
+        {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, 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, 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, 0},    // Bulk erase
+        {JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},     // Sector erase
+        {JEDEC_BE_52, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},  // Block erase
+        {JEDEC_AAI_WORD_PROGRAM, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Auto Address Increment
+};
+
+static OPCODES O_EXISTING = {};
+
+/* pretty printing functions */
+static void prettyprint_opcodes(OPCODES *ops)
+{
+       OPCODE oc;
+       const char *t;
+       const char *a;
+       uint8_t i;
+       static const char *const spi_type[4] = {
+               "read  w/o addr",
+               "write w/o addr",
+               "read  w/  addr",
+               "write w/  addr"
+       };
+       static const char *const atomic_type[3] = {
+               "none",
+               " 0  ",
+               " 1  "
+       };
+
+       if (ops == NULL)
+               return;
+
+       msg_pdbg2("        OP        Type      Pre-OP\n");
+       for (i = 0; i < 8; i++) {
+               oc = ops->opcode[i];
+               t = (oc.spi_type > 3) ? "invalid" : spi_type[oc.spi_type];
+               a = (oc.atomic > 2) ? "invalid" : atomic_type[oc.atomic];
+               msg_pdbg2("op[%d]: 0x%02x, %s, %s\n", i, oc.opcode, t, a);
+       }
+       msg_pdbg2("Pre-OP 0: 0x%02x, Pre-OP 1: 0x%02x\n", ops->preop[0],
+                ops->preop[1]);
+}
+
+#define pprint_reg(reg, bit, val, sep) msg_pdbg("%s=%d" sep, #bit, (val & reg##_##bit)>>reg##_##bit##_OFF)
+
+static void prettyprint_ich9_reg_hsfs(uint16_t reg_val)
+{
+       msg_pdbg("HSFS: ");
+       pprint_reg(HSFS, FDONE, reg_val, ", ");
+       pprint_reg(HSFS, FCERR, reg_val, ", ");
+       pprint_reg(HSFS, AEL, reg_val, ", ");
+       pprint_reg(HSFS, BERASE, reg_val, ", ");
+       pprint_reg(HSFS, SCIP, reg_val, ", ");
+       pprint_reg(HSFS, FDOPSS, reg_val, ", ");
+       pprint_reg(HSFS, FDV, reg_val, ", ");
+       pprint_reg(HSFS, FLOCKDN, reg_val, "\n");
+}
+
+static void prettyprint_ich9_reg_hsfc(uint16_t reg_val)
+{
+       msg_pdbg("HSFC: ");
+       pprint_reg(HSFC, FGO, reg_val, ", ");
+       pprint_reg(HSFC, FCYCLE, reg_val, ", ");
+       pprint_reg(HSFC, FDBC, reg_val, ", ");
+       pprint_reg(HSFC, SME, reg_val, "\n");
+}
+
+static void prettyprint_ich9_reg_ssfs(uint32_t reg_val)
+{
+       msg_pdbg("SSFS: ");
+       pprint_reg(SSFS, SCIP, reg_val, ", ");
+       pprint_reg(SSFS, FDONE, reg_val, ", ");
+       pprint_reg(SSFS, FCERR, reg_val, ", ");
+       pprint_reg(SSFS, AEL, reg_val, "\n");
+}
+
+static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
+{
+       msg_pdbg("SSFC: ");
+       pprint_reg(SSFC, SCGO, reg_val, ", ");
+       pprint_reg(SSFC, ACS, reg_val, ", ");
+       pprint_reg(SSFC, SPOP, reg_val, ", ");
+       pprint_reg(SSFC, COP, reg_val, ", ");
+       pprint_reg(SSFC, DBC, reg_val, ", ");
+       pprint_reg(SSFC, SME, reg_val, ", ");
+       pprint_reg(SSFC, SCF, reg_val, "\n");
+}
+
+static uint8_t lookup_spi_type(uint8_t opcode)
+{
+       int a;
+
+       for (a = 0; a < ARRAY_SIZE(POSSIBLE_OPCODES); a++) {
+               if (POSSIBLE_OPCODES[a].opcode == opcode)
+                       return POSSIBLE_OPCODES[a].spi_type;
+       }
+
+       return 0xFF;
+}
+
+static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
+{
+       uint8_t spi_type;
+
+       spi_type = lookup_spi_type(opcode);
+       if (spi_type > 3) {
+               /* Try to guess spi type from read/write sizes.
+                * 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 (readcnt == 0)
+                       /* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
+                        * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
+                        * bytes are actual the address, they go to the bus anyhow
+                        */
+                       spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
+               else if (writecnt == 1) // and readcnt is > 0
+                       spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
+               else if (writecnt == 4) // and readcnt is > 0
+                       spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
+               else // we have an invalid case
+                       return SPI_INVALID_LENGTH;
+       }
+       int oppos = 2;  // use original JEDEC_BE_D8 offset
+       curopcodes->opcode[oppos].opcode = opcode;
+       curopcodes->opcode[oppos].spi_type = spi_type;
+       program_opcodes(curopcodes, 0);
+       oppos = find_opcode(curopcodes, opcode);
+       msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
+       return oppos;
+}
+
+static int find_opcode(OPCODES *op, uint8_t opcode)
+{
+       int a;
+
+       if (op == NULL) {
+               msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+               return -1;
+       }
+
+       for (a = 0; a < 8; a++) {
+               if (op->opcode[a].opcode == opcode)
+                       return a;
+       }
+
+       return -1;
+}
+
+static int find_preop(OPCODES *op, uint8_t preop)
+{
+       int a;
+
+       if (op == NULL) {
+               msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+               return -1;
+       }
+
+       for (a = 0; a < 2; a++) {
+               if (op->preop[a] == preop)
+                       return a;
+       }
+
+       return -1;
+}
+
+/* Create a struct OPCODES based on what we find in the locked down chipset. */
+static int generate_opcodes(OPCODES * op)
+{
+       int a;
+       uint16_t preop, optype;
+       uint32_t opmenu[2];
+
+       if (op == NULL) {
+               msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+               return -1;
+       }
+
+       switch (ich_generation) {
+       case CHIPSET_ICH7:
+               preop = REGREAD16(ICH7_REG_PREOP);
+               optype = REGREAD16(ICH7_REG_OPTYPE);
+               opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
+               opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
+               break;
+       case CHIPSET_ICH8:
+       default:                /* Future version might behave the same */
+               preop = REGREAD16(ICH9_REG_PREOP);
+               optype = REGREAD16(ICH9_REG_OPTYPE);
+               opmenu[0] = REGREAD32(ICH9_REG_OPMENU);
+               opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4);
+               break;
+       }
+
+       op->preop[0] = (uint8_t) preop;
+       op->preop[1] = (uint8_t) (preop >> 8);
+
+       for (a = 0; a < 8; a++) {
+               op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
+               optype >>= 2;
+       }
+
+       for (a = 0; a < 4; a++) {
+               op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
+               opmenu[0] >>= 8;
+       }
+
+       for (a = 4; a < 8; a++) {
+               op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
+               opmenu[1] >>= 8;
+       }
+
+       /* No preopcodes used by default. */
+       for (a = 0; a < 8; a++)
+               op->opcode[a].atomic = 0;
+
+       return 0;
+}
+
+static int program_opcodes(OPCODES *op, int enable_undo)
+{
+       uint8_t a;
+       uint16_t preop, optype;
+       uint32_t opmenu[2];
+
+       /* Program Prefix Opcodes */
+       /* 0:7 Prefix Opcode 1 */
+       preop = (op->preop[0]);
+       /* 8:16 Prefix Opcode 2 */
+       preop |= ((uint16_t) op->preop[1]) << 8;
+
+       /* Program Opcode Types 0 - 7 */
+       optype = 0;
+       for (a = 0; a < 8; a++) {
+               optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
+       }
+
+       /* Program Allowable Opcodes 0 - 3 */
+       opmenu[0] = 0;
+       for (a = 0; a < 4; a++) {
+               opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
+       }
+
+       /*Program Allowable Opcodes 4 - 7 */
+       opmenu[1] = 0;
+       for (a = 4; a < 8; a++) {
+               opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
+       }
+
+       msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
+       switch (ich_generation) {
+       case CHIPSET_ICH7:
+               /* Register undo only for enable_undo=1, i.e. first call. */
+               if (enable_undo) {
+                       rmmio_valw(ich_spibar + ICH7_REG_PREOP);
+                       rmmio_valw(ich_spibar + ICH7_REG_OPTYPE);
+                       rmmio_vall(ich_spibar + ICH7_REG_OPMENU);
+                       rmmio_vall(ich_spibar + ICH7_REG_OPMENU + 4);
+               }
+               mmio_writew(preop, ich_spibar + ICH7_REG_PREOP);
+               mmio_writew(optype, ich_spibar + ICH7_REG_OPTYPE);
+               mmio_writel(opmenu[0], ich_spibar + ICH7_REG_OPMENU);
+               mmio_writel(opmenu[1], ich_spibar + ICH7_REG_OPMENU + 4);
+               break;
+       case CHIPSET_ICH8:
+       default:                /* Future version might behave the same */
+               /* Register undo only for enable_undo=1, i.e. first call. */
+               if (enable_undo) {
+                       rmmio_valw(ich_spibar + ICH9_REG_PREOP);
+                       rmmio_valw(ich_spibar + ICH9_REG_OPTYPE);
+                       rmmio_vall(ich_spibar + ICH9_REG_OPMENU);
+                       rmmio_vall(ich_spibar + ICH9_REG_OPMENU + 4);
+               }
+               mmio_writew(preop, ich_spibar + ICH9_REG_PREOP);
+               mmio_writew(optype, ich_spibar + ICH9_REG_OPTYPE);
+               mmio_writel(opmenu[0], ich_spibar + ICH9_REG_OPMENU);
+               mmio_writel(opmenu[1], ich_spibar + ICH9_REG_OPMENU + 4);
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * Returns -1 if at least one mandatory opcode is inaccessible, 0 otherwise.
+ * FIXME: this should also check for
+ *   - at least one probing opcode (RDID (incl. AT25F variants?), REMS, RES?)
+ *   - at least one erasing opcode (lots.)
+ *   - at least one program opcode (BYTE_PROGRAM, AAI_WORD_PROGRAM, ...?)
+ *   - necessary preops? (EWSR, WREN, ...?)
+ */
+static int ich_missing_opcodes()
+{
+       uint8_t ops[] = {
+               JEDEC_READ,
+               JEDEC_RDSR,
+               0
+       };
+       int i = 0;
+       while (ops[i] != 0) {
+               msg_pspew("checking for opcode 0x%02x\n", ops[i]);
+               if (find_opcode(curopcodes, ops[i]) == -1)
+                       return -1;
+               i++;
+       }
+       return 0;
+}
+
+/*
+ * Try to set BBAR (BIOS Base Address Register), but read back the value in case
+ * it didn't stick.
+ */
+static void ich_set_bbar(uint32_t min_addr)
+{
+       int bbar_off;
+       switch (ich_generation) {
+       case CHIPSET_ICH7:
+               bbar_off = 0x50;
+               break;
+       case CHIPSET_ICH8:
+               msg_perr("BBAR offset is unknown on ICH8!\n");
+               return;
+       case CHIPSET_ICH9:
+       default:                /* Future version might behave the same */
+               bbar_off = ICH9_REG_BBAR;
+               break;
+       }
+       
+       ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & ~BBAR_MASK;
+       if (ichspi_bbar) {
+               msg_pdbg("Reserved bits in BBAR not zero: 0x%08x\n",
+                        ichspi_bbar);
+       }
+       min_addr &= BBAR_MASK;
+       ichspi_bbar |= min_addr;
+       rmmio_writel(ichspi_bbar, ich_spibar + bbar_off);
+       ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & BBAR_MASK;
+
+       /* We don't have any option except complaining. And if the write
+        * failed, the restore will fail as well, so no problem there.
+        */
+       if (ichspi_bbar != min_addr)
+               msg_perr("Setting BBAR to 0x%08x failed! New value: 0x%08x.\n",
+                        min_addr, ichspi_bbar);
+}
+
+/* Read len bytes from the fdata/spid register into the data array.
+ *
+ * Note that using len > flash->pgm->spi.max_data_read will return garbage or
+ * may even crash.
+ */
+static void ich_read_data(uint8_t *data, int len, int reg0_off)
+ {
+       int i;
+       uint32_t temp32 = 0;
+
+       for (i = 0; i < len; i++) {
+               if ((i % 4) == 0)
+                       temp32 = REGREAD32(reg0_off + i);
+
+               data[i] = (temp32 >> ((i % 4) * 8)) & 0xff;
+       }
+}
+
+/* Fill len bytes from the data array into the fdata/spid registers.
+ *
+ * Note that using len > flash->pgm->spi.max_data_write will trash the registers
+ * following the data registers.
+ */
+static void ich_fill_data(const uint8_t *data, int len, int reg0_off)
+{
+       uint32_t temp32 = 0;
+       int i;
+
+       if (len <= 0)
+               return;
+
+       for (i = 0; i < len; i++) {
+               if ((i % 4) == 0)
+                       temp32 = 0;
+
+               temp32 |= ((uint32_t) data[i]) << ((i % 4) * 8);
+
+               if ((i % 4) == 3) /* 32 bits are full, write them to regs. */
+                       REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+       }
+       i--;
+       if ((i % 4) != 3) /* Write remaining data to regs. */
+               REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+}
+
+/* This function generates OPCODES from or programs OPCODES to ICH according to
+ * the chipset's SPI configuration lock.
+ *
+ * It should be called before ICH sends any spi command.
+ */
+static int ich_init_opcodes(void)
+{
+       int rc = 0;
+       OPCODES *curopcodes_done;
+
+       if (curopcodes)
+               return 0;
+
+       if (ichspi_lock) {
+               msg_pdbg("Reading OPCODES... ");
+               curopcodes_done = &O_EXISTING;
+               rc = generate_opcodes(curopcodes_done);
+       } else {
+               msg_pdbg("Programming OPCODES... ");
+               curopcodes_done = &O_ST_M25P;
+               rc = program_opcodes(curopcodes_done, 1);
+       }
+
+       if (rc) {
+               curopcodes = NULL;
+               msg_perr("failed\n");
+               return 1;
+       } else {
+               curopcodes = curopcodes_done;
+               msg_pdbg("done\n");
+               prettyprint_opcodes(curopcodes);
+               return 0;
+       }
+}
+
+static int ich7_run_opcode(OPCODE op, uint32_t offset,
+                          uint8_t datalength, uint8_t * data, int maxdata)
+{
+       int write_cmd = 0;
+       int timeout;
+       uint32_t temp32;
+       uint16_t temp16;
+       uint64_t opmenu;
+       int opcode_index;
+
+       /* Is it a write command? */
+       if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
+           || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
+               write_cmd = 1;
+       }
+
+       timeout = 100 * 60;     /* 60 ms are 9.6 million cycles at 16 MHz. */
+       while ((REGREAD16(ICH7_REG_SPIS) & SPIS_SCIP) && --timeout) {
+               programmer_delay(10);
+       }
+       if (!timeout) {
+               msg_perr("Error: SCIP never cleared!\n");
+               return 1;
+       }
+
+       /* Program offset in flash into SPIA while preserving reserved bits. */
+       temp32 = REGREAD32(ICH7_REG_SPIA) & ~0x00FFFFFF;
+       REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF) | temp32);
+
+       /* Program data into SPID0 to N */
+       if (write_cmd && (datalength != 0))
+               ich_fill_data(data, datalength, ICH7_REG_SPID0);
+
+       /* Assemble SPIS */
+       temp16 = REGREAD16(ICH7_REG_SPIS);
+       /* keep reserved bits */
+       temp16 &= SPIS_RESERVED_MASK;
+       /* clear error status registers */
+       temp16 |= (SPIS_CDS | SPIS_FCERR);
+       REGWRITE16(ICH7_REG_SPIS, temp16);
+
+       /* Assemble SPIC */
+       temp16 = 0;
+
+       if (datalength != 0) {
+               temp16 |= SPIC_DS;
+               temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
+       }
+
+       /* Select opcode */
+       opmenu = REGREAD32(ICH7_REG_OPMENU);
+       opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
+
+       for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+               if ((opmenu & 0xff) == op.opcode) {
+                       break;
+               }
+               opmenu >>= 8;
+       }
+       if (opcode_index == 8) {
+               msg_pdbg("Opcode %x not found.\n", op.opcode);
+               return 1;
+       }
+       temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
+
+       timeout = 100 * 60;     /* 60 ms are 9.6 million cycles at 16 MHz. */
+       /* Handle Atomic. Atomic commands include three steps:
+           - sending the preop (mainly EWSR or WREN)
+           - sending the main command
+           - waiting for the busy bit (WIP) to be cleared
+          This means the timeout must be sufficient for chip erase
+          of slow high-capacity chips.
+        */
+       switch (op.atomic) {
+       case 2:
+               /* Select second preop. */
+               temp16 |= SPIC_SPOP;
+               /* And fall through. */
+       case 1:
+               /* Atomic command (preop+op) */
+               temp16 |= SPIC_ACS;
+               timeout = 100 * 1000 * 60;      /* 60 seconds */
+               break;
+       }
+
+       /* Start */
+       temp16 |= SPIC_SCGO;
+
+       /* write it */
+       REGWRITE16(ICH7_REG_SPIC, temp16);
+
+       /* Wait for Cycle Done Status or Flash Cycle Error. */
+       while (((REGREAD16(ICH7_REG_SPIS) & (SPIS_CDS | SPIS_FCERR)) == 0) &&
+              --timeout) {
+               programmer_delay(10);
+       }
+       if (!timeout) {
+               msg_perr("timeout, ICH7_REG_SPIS=0x%04x\n",
+                        REGREAD16(ICH7_REG_SPIS));
+               return 1;
+       }
+
+       /* FIXME: make sure we do not needlessly cause transaction errors. */
+       temp16 = REGREAD16(ICH7_REG_SPIS);
+       if (temp16 & SPIS_FCERR) {
+               msg_perr("Transaction error!\n");
+               /* keep reserved bits */
+               temp16 &= SPIS_RESERVED_MASK;
+               REGWRITE16(ICH7_REG_SPIS, temp16 | SPIS_FCERR);
+               return 1;
+       }
+
+       if ((!write_cmd) && (datalength != 0))
+               ich_read_data(data, datalength, ICH7_REG_SPID0);
+
+       return 0;
+}
+
+static int ich9_run_opcode(OPCODE op, uint32_t offset,
+                          uint8_t datalength, uint8_t * data)
+{
+       int write_cmd = 0;
+       int timeout;
+       uint32_t temp32;
+       uint64_t opmenu;
+       int opcode_index;
+
+       /* Is it a write command? */
+       if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
+           || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
+               write_cmd = 1;
+       }
+
+       timeout = 100 * 60;     /* 60 ms are 9.6 million cycles at 16 MHz. */
+       while ((REGREAD8(ICH9_REG_SSFS) & SSFS_SCIP) && --timeout) {
+               programmer_delay(10);
+       }
+       if (!timeout) {
+               msg_perr("Error: SCIP never cleared!\n");
+               return 1;
+       }
+
+       /* Program offset in flash into FADDR while preserve the reserved bits
+        * and clearing the 25. address bit which is only useable in hwseq. */
+       temp32 = REGREAD32(ICH9_REG_FADDR) & ~0x01FFFFFF;
+       REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF) | temp32);
+
+       /* Program data into FDATA0 to N */
+       if (write_cmd && (datalength != 0))
+               ich_fill_data(data, datalength, ICH9_REG_FDATA0);
+
+       /* Assemble SSFS + SSFC */
+       temp32 = REGREAD32(ICH9_REG_SSFS);
+       /* Keep reserved bits only */
+       temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
+       /* Clear cycle done and cycle error status registers */
+       temp32 |= (SSFS_FDONE | SSFS_FCERR);
+       REGWRITE32(ICH9_REG_SSFS, temp32);
+
+       /* Use 20 MHz */
+       temp32 |= SSFC_SCF_20MHZ;
+
+       /* Set data byte count (DBC) and data cycle bit (DS) */
+       if (datalength != 0) {
+               uint32_t datatemp;
+               temp32 |= SSFC_DS;
+               datatemp = ((((uint32_t)datalength - 1) << SSFC_DBC_OFF) &
+                           SSFC_DBC);
+               temp32 |= datatemp;
+       }
+
+       /* Select opcode */
+       opmenu = REGREAD32(ICH9_REG_OPMENU);
+       opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32;
+
+       for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+               if ((opmenu & 0xff) == op.opcode) {
+                       break;
+               }
+               opmenu >>= 8;
+       }
+       if (opcode_index == 8) {
+               msg_pdbg("Opcode %x not found.\n", op.opcode);
+               return 1;
+       }
+       temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
+
+       timeout = 100 * 60;     /* 60 ms are 9.6 million cycles at 16 MHz. */
+       /* Handle Atomic. Atomic commands include three steps:
+           - sending the preop (mainly EWSR or WREN)
+           - sending the main command
+           - waiting for the busy bit (WIP) to be cleared
+          This means the timeout must be sufficient for chip erase
+          of slow high-capacity chips.
+        */
+       switch (op.atomic) {
+       case 2:
+               /* Select second preop. */
+               temp32 |= SSFC_SPOP;
+               /* And fall through. */
+       case 1:
+               /* Atomic command (preop+op) */
+               temp32 |= SSFC_ACS;
+               timeout = 100 * 1000 * 60;      /* 60 seconds */
+               break;
+       }
+
+       /* Start */
+       temp32 |= SSFC_SCGO;
+
+       /* write it */
+       REGWRITE32(ICH9_REG_SSFS, temp32);
+
+       /* Wait for Cycle Done Status or Flash Cycle Error. */
+       while (((REGREAD32(ICH9_REG_SSFS) & (SSFS_FDONE | SSFS_FCERR)) == 0) &&
+              --timeout) {
+               programmer_delay(10);
+       }
+       if (!timeout) {
+               msg_perr("timeout, ICH9_REG_SSFS=0x%08x\n",
+                        REGREAD32(ICH9_REG_SSFS));
+               return 1;
+       }
+
+       /* FIXME make sure we do not needlessly cause transaction errors. */
+       temp32 = REGREAD32(ICH9_REG_SSFS);
+       if (temp32 & SSFS_FCERR) {
+               msg_perr("Transaction error!\n");
+               prettyprint_ich9_reg_ssfs(temp32);
+               prettyprint_ich9_reg_ssfc(temp32);
+               /* keep reserved bits */
+               temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
+               /* Clear the transaction error. */
+               REGWRITE32(ICH9_REG_SSFS, temp32 | SSFS_FCERR);
+               return 1;
+       }
+
+       if ((!write_cmd) && (datalength != 0))
+               ich_read_data(data, datalength, ICH9_REG_FDATA0);
+
+       return 0;
+}
+
+static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
+                     uint8_t datalength, uint8_t * data)
+{
+       /* max_data_read == max_data_write for all Intel/VIA SPI masters */
+       uint8_t maxlength = flash->pgm->spi.max_data_read;
+
+       if (ich_generation == CHIPSET_ICH_UNKNOWN) {
+               msg_perr("%s: unsupported chipset\n", __func__);
+               return -1;
+       }
+
+       if (datalength > maxlength) {
+               msg_perr("%s: Internal command size error for "
+                       "opcode 0x%02x, got datalength=%i, want <=%i\n",
+                       __func__, op.opcode, datalength, maxlength);
+               return SPI_INVALID_LENGTH;
+       }
+
+       switch (ich_generation) {
+       case CHIPSET_ICH7:
+               return ich7_run_opcode(op, offset, datalength, data, maxlength);
+       case CHIPSET_ICH8:
+       default:                /* Future version might behave the same */
+               return ich9_run_opcode(op, offset, datalength, data);
+       }
+}
+
+static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                               unsigned int readcnt,
+                               const unsigned char *writearr,
+                               unsigned char *readarr)
+{
+       int result;
+       int opcode_index = -1;
+       const unsigned char cmd = *writearr;
+       OPCODE *opcode;
+       uint32_t addr = 0;
+       uint8_t *data;
+       int count;
+
+       /* find cmd in opcodes-table */
+       opcode_index = find_opcode(curopcodes, cmd);
+       if (opcode_index == -1) {
+               if (!ichspi_lock)
+                       opcode_index = reprogram_opcode_on_the_fly(cmd, writecnt, readcnt);
+               if (opcode_index == SPI_INVALID_LENGTH) {
+                       msg_pdbg("OPCODE 0x%02x has unsupported length, will not execute.\n", cmd);
+                       return SPI_INVALID_LENGTH;
+               } else if (opcode_index == -1) {
+                       msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\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)) {
+               msg_perr("%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)) {
+               msg_perr("%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)) {
+               msg_perr("%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)) {
+               msg_perr("%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) {
+               addr = (writearr[1] << 16) |
+                   (writearr[2] << 8) | (writearr[3] << 0);
+               if (addr < ichspi_bbar) {
+                       msg_perr("%s: Address 0x%06x below allowed "
+                                "range 0x%06x-0xffffff\n", __func__,
+                                addr, ichspi_bbar);
+                       return SPI_INVALID_ADDRESS;
+               }
+       }
+
+       /* Translate read/write array/count.
+        * The maximum data length is identical for the maximum read length and
+        * for the maximum write length excluding opcode and address. Opcode and
+        * address are stored in separate registers, not in the data registers
+        * and are thus not counted towards data length. The only exception
+        * applies if the opcode definition (un)intentionally classifies said
+        * opcode incorrectly as non-address opcode or vice versa. */
+       if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
+               data = (uint8_t *) (writearr + 1);
+               count = writecnt - 1;
+       } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
+               data = (uint8_t *) (writearr + 4);
+               count = writecnt - 4;
+       } else {
+               data = (uint8_t *) readarr;
+               count = readcnt;
+       }
+
+       result = run_opcode(flash, *opcode, addr, count, data);
+       if (result) {
+               msg_pdbg("Running OPCODE 0x%02x failed ", opcode->opcode);
+               if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
+                   (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS)) {
+                       msg_pdbg("at address 0x%06x ", addr);
+               }
+               msg_pdbg("(payload length was %d).\n", count);
+
+               /* Print out the data array if it contains data to write.
+                * Errors are detected before the received data is read back into
+                * the array so it won't make sense to print it then. */
+               if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
+                   (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) {
+                       int i;
+                       msg_pspew("The data was:\n");
+                       for (i = 0; i < count; i++){
+                               msg_pspew("%3d: 0x%02x\n", i, data[i]);
+                       }
+               }
+       }
+
+       return result;
+}
+
+static struct hwseq_data {
+       uint32_t size_comp0;
+       uint32_t size_comp1;
+} hwseq_data;
+
+/* Sets FLA in FADDR to (addr & 0x01FFFFFF) without touching other bits. */
+static void ich_hwseq_set_addr(uint32_t addr)
+{
+       uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~0x01FFFFFF;
+       REGWRITE32(ICH9_REG_FADDR, (addr & 0x01FFFFFF) | addr_old);
+}
+
+/* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes
+ * of the block containing this address. May return nonsense if the address is
+ * not valid. The erase block size for a specific address depends on the flash
+ * partition layout as specified by FPB and the partition properties as defined
+ * by UVSCC and LVSCC respectively. An alternative to implement this method
+ * would be by querying FPB and the respective VSCC register directly.
+ */
+static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
+{
+       uint8_t enc_berase;
+       static const uint32_t const dec_berase[4] = {
+               256,
+               4 * 1024,
+               8 * 1024,
+               64 * 1024
+       };
+
+       ich_hwseq_set_addr(addr);
+       enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >>
+                    HSFS_BERASE_OFF;
+       return dec_berase[enc_berase];
+}
+
+/* Polls for Cycle Done Status, Flash Cycle Error or timeout in 8 us intervals.
+   Resets all error flags in HSFS.
+   Returns 0 if the cycle completes successfully without errors within
+   timeout us, 1 on errors. */
+static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
+                                            unsigned int len)
+{
+       uint16_t hsfs;
+       uint32_t addr;
+
+       timeout /= 8; /* scale timeout duration to counter */
+       while ((((hsfs = REGREAD16(ICH9_REG_HSFS)) &
+                (HSFS_FDONE | HSFS_FCERR)) == 0) &&
+              --timeout) {
+               programmer_delay(8);
+       }
+       REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+       if (!timeout) {
+               addr = REGREAD32(ICH9_REG_FADDR) & 0x01FFFFFF;
+               msg_perr("Timeout error between offset 0x%08x and "
+                        "0x%08x (= 0x%08x + %d)!\n",
+                        addr, addr + len - 1, addr, len - 1);
+               prettyprint_ich9_reg_hsfs(hsfs);
+               prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC));
+               return 1;
+       }
+
+       if (hsfs & HSFS_FCERR) {
+               addr = REGREAD32(ICH9_REG_FADDR) & 0x01FFFFFF;
+               msg_perr("Transaction error between offset 0x%08x and "
+                        "0x%08x (= 0x%08x + %d)!\n",
+                        addr, addr + len - 1, addr, len - 1);
+               prettyprint_ich9_reg_hsfs(hsfs);
+               prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC));
+               return 1;
+       }
+       return 0;
+}
+
+static int ich_hwseq_probe(struct flashctx *flash)
+{
+       uint32_t total_size, boundary;
+       uint32_t erase_size_low, size_low, erase_size_high, size_high;
+       struct block_eraser *eraser;
+
+       total_size = hwseq_data.size_comp0 + hwseq_data.size_comp1;
+       msg_cdbg("Found %d attached SPI flash chip",
+                (hwseq_data.size_comp1 != 0) ? 2 : 1);
+       if (hwseq_data.size_comp1 != 0)
+               msg_cdbg("s with a combined");
+       else
+               msg_cdbg(" with a");
+       msg_cdbg(" density of %d kB.\n", total_size / 1024);
+       flash->total_size = total_size / 1024;
+
+       eraser = &(flash->block_erasers[0]);
+       boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12;
+       size_high = total_size - boundary;
+       erase_size_high = ich_hwseq_get_erase_block_size(boundary);
+
+       if (boundary == 0) {
+               msg_cdbg("There is only one partition containing the whole "
+                        "address space (0x%06x - 0x%06x).\n", 0, size_high-1);
+               eraser->eraseblocks[0].size = erase_size_high;
+               eraser->eraseblocks[0].count = size_high / erase_size_high;
+               msg_cdbg("There are %d erase blocks with %d B each.\n",
+                        size_high / erase_size_high, erase_size_high);
+       } else {
+               msg_cdbg("The flash address space (0x%06x - 0x%06x) is divided "
+                        "at address 0x%06x in two partitions.\n",
+                        0, size_high-1, boundary);
+               size_low = total_size - size_high;
+               erase_size_low = ich_hwseq_get_erase_block_size(0);
+
+               eraser->eraseblocks[0].size = erase_size_low;
+               eraser->eraseblocks[0].count = size_low / erase_size_low;
+               msg_cdbg("The first partition ranges from 0x%06x to 0x%06x.\n",
+                        0, size_low-1);
+               msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+                        size_low / erase_size_low, erase_size_low);
+
+               eraser->eraseblocks[1].size = erase_size_high;
+               eraser->eraseblocks[1].count = size_high / erase_size_high;
+               msg_cdbg("The second partition ranges from 0x%06x to 0x%06x.\n",
+                        boundary, size_high-1);
+               msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+                        size_high / erase_size_high, erase_size_high);
+       }
+       flash->tested = TEST_OK_PREW;
+       return 1;
+}
+
+static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
+                                unsigned int len)
+{
+       uint32_t erase_block;
+       uint16_t hsfc;
+       uint32_t timeout = 5000 * 1000; /* 5 s for max 64 kB */
+
+       erase_block = ich_hwseq_get_erase_block_size(addr);
+       if (len != erase_block) {
+               msg_cerr("Erase block size for address 0x%06x is %d B, "
+                        "but requested erase block size is %d B. "
+                        "Not erasing anything.\n", addr, erase_block, len);
+               return -1;
+       }
+
+       /* Although the hardware supports this (it would erase the whole block
+        * containing the address) we play safe here. */
+       if (addr % erase_block != 0) {
+               msg_cerr("Erase address 0x%06x is not aligned to the erase "
+                        "block boundary (any multiple of %d). "
+                        "Not erasing anything.\n", addr, erase_block);
+               return -1;
+       }
+
+       if (addr + len > flash->total_size * 1024) {
+               msg_perr("Request to erase some inaccessible memory address(es)"
+                        " (addr=0x%x, len=%d). "
+                        "Not erasing anything.\n", addr, len);
+               return -1;
+       }
+
+       msg_pdbg("Erasing %d bytes starting at 0x%06x.\n", len, addr);
+
+       /* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */
+       REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+
+       hsfc = REGREAD16(ICH9_REG_HSFC);
+       hsfc &= ~HSFC_FCYCLE; /* clear operation */
+       hsfc |= (0x3 << HSFC_FCYCLE_OFF); /* set erase operation */
+       hsfc |= HSFC_FGO; /* start */
+       msg_pdbg("HSFC used for block erasing: ");
+       prettyprint_ich9_reg_hsfc(hsfc);
+       REGWRITE16(ICH9_REG_HSFC, hsfc);
+
+       if (ich_hwseq_wait_for_cycle_complete(timeout, len))
+               return -1;
+       return 0;
+}
+
+static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
+                         unsigned int addr, unsigned int len)
+{
+       uint16_t hsfc;
+       uint16_t timeout = 100 * 60;
+       uint8_t block_len;
+
+       if (addr + len > flash->total_size * 1024) {
+               msg_perr("Request to read from an inaccessible memory address "
+                        "(addr=0x%x, len=%d).\n", addr, len);
+               return -1;
+       }
+
+       msg_pdbg("Reading %d bytes starting at 0x%06x.\n", len, addr);
+       /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */
+       REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+
+       while (len > 0) {
+               block_len = min(len, flash->pgm->opaque.max_data_read);
+               ich_hwseq_set_addr(addr);
+               hsfc = REGREAD16(ICH9_REG_HSFC);
+               hsfc &= ~HSFC_FCYCLE; /* set read operation */
+               hsfc &= ~HSFC_FDBC; /* clear byte count */
+               /* set byte count */
+               hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC);
+               hsfc |= HSFC_FGO; /* start */
+               REGWRITE16(ICH9_REG_HSFC, hsfc);
+
+               if (ich_hwseq_wait_for_cycle_complete(timeout, block_len))
+                       return 1;
+               ich_read_data(buf, block_len, ICH9_REG_FDATA0);
+               addr += block_len;
+               buf += block_len;
+               len -= block_len;
+       }
+       return 0;
+}
+
+static int ich_hwseq_write(struct flashctx *flash, uint8_t *buf,
+                          unsigned int addr, unsigned int len)
+{
+       uint16_t hsfc;
+       uint16_t timeout = 100 * 60;
+       uint8_t block_len;
+
+       if (addr + len > flash->total_size * 1024) {
+               msg_perr("Request to write to an inaccessible memory address "
+                        "(addr=0x%x, len=%d).\n", addr, len);
+               return -1;
+       }
+
+       msg_pdbg("Writing %d bytes starting at 0x%06x.\n", len, addr);
+       /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */
+       REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+
+       while (len > 0) {
+               ich_hwseq_set_addr(addr);
+               block_len = min(len, flash->pgm->opaque.max_data_write);
+               ich_fill_data(buf, block_len, ICH9_REG_FDATA0);
+               hsfc = REGREAD16(ICH9_REG_HSFC);
+               hsfc &= ~HSFC_FCYCLE; /* clear operation */
+               hsfc |= (0x2 << HSFC_FCYCLE_OFF); /* set write operation */
+               hsfc &= ~HSFC_FDBC; /* clear byte count */
+               /* set byte count */
+               hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC);
+               hsfc |= HSFC_FGO; /* start */
+               REGWRITE16(ICH9_REG_HSFC, hsfc);
+
+               if (ich_hwseq_wait_for_cycle_complete(timeout, block_len))
+                       return -1;
+               addr += block_len;
+               buf += block_len;
+               len -= block_len;
+       }
+       return 0;
+}
+
+static int ich_spi_send_multicommand(struct flashctx *flash,
+                                    struct spi_command *cmds)
+{
+       int 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) {
+                                       msg_perr("%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) {
+                                       oppos = reprogram_opcode_on_the_fly((cmds + 1)->writearr[0], (cmds + 1)->writecnt, (cmds + 1)->readcnt);
+                                       if (oppos == -1)
+                                               continue;
+                                       curopcodes->opcode[oppos].atomic = preoppos + 1;
+                                       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.
+                        */
+               }
+               ret = ich_spi_send_command(flash, 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;
+}
+
+#define ICH_BMWAG(x) ((x >> 24) & 0xff)
+#define ICH_BMRAG(x) ((x >> 16) & 0xff)
+#define ICH_BRWA(x)  ((x >>  8) & 0xff)
+#define ICH_BRRA(x)  ((x >>  0) & 0xff)
+
+/* returns 0 if region is unused or r/w */
+static int ich9_handle_frap(uint32_t frap, int i)
+{
+       static const char *const access_names[4] = {
+               "locked", "read-only", "write-only", "read-write"
+       };
+       static const char *const region_names[5] = {
+               "Flash Descriptor", "BIOS", "Management Engine",
+               "Gigabit Ethernet", "Platform Data"
+       };
+       uint32_t base, limit;
+       int rwperms = (((ICH_BRWA(frap) >> i) & 1) << 1) |
+                     (((ICH_BRRA(frap) >> i) & 1) << 0);
+       int offset = ICH9_REG_FREG0 + i * 4;
+       uint32_t freg = mmio_readl(ich_spibar + offset);
+
+       base  = ICH_FREG_BASE(freg);
+       limit = ICH_FREG_LIMIT(freg);
+       if (base > limit) {
+               /* this FREG is disabled */
+               msg_pdbg2("0x%02X: 0x%08x FREG%i: %s region is unused.\n",
+                         offset, freg, i, region_names[i]);
+               return 0;
+       }
+       msg_pdbg("0x%02X: 0x%08x ", offset, freg);
+       if (rwperms == 0x3) {
+               msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i,
+                        region_names[i], base, (limit | 0x0fff),
+                        access_names[rwperms]);
+               return 0;
+       }
+
+       msg_pinfo("FREG%i: WARNING: %s region (0x%08x-0x%08x) is %s.\n", i,
+                 region_names[i], base, (limit | 0x0fff),
+                 access_names[rwperms]);
+       return 1;
+}
+
+       /* In contrast to FRAP and the master section of the descriptor the bits
+        * in the PR registers have an inverted meaning. The bits in FRAP
+        * indicate read and write access _grant_. Here they indicate read
+        * and write _protection_ respectively. If both bits are 0 the address
+        * bits are ignored.
+        */
+#define ICH_PR_PERMS(pr)       (((~((pr) >> PR_RP_OFF) & 1) << 0) | \
+                                ((~((pr) >> PR_WP_OFF) & 1) << 1))
+
+/* returns 0 if range is unused (i.e. r/w) */
+static int ich9_handle_pr(int i)
+{
+       static const char *const access_names[3] = {
+               "locked", "read-only", "write-only"
+       };
+       uint8_t off = ICH9_REG_PR0 + (i * 4);
+       uint32_t pr = mmio_readl(ich_spibar + off);
+       unsigned int rwperms = ICH_PR_PERMS(pr);
+
+       if (rwperms == 0x3) {
+               msg_pdbg2("0x%02X: 0x%08x (PR%u is unused)\n", off, pr, i);
+               return 0;
+       }
+
+       msg_pdbg("0x%02X: 0x%08x ", off, pr);
+       msg_pinfo("PR%u: WARNING: 0x%08x-0x%08x is %s.\n", i, ICH_FREG_BASE(pr),
+                 ICH_FREG_LIMIT(pr) | 0x0fff, access_names[rwperms]);
+       return 1;
+}
+
+/* Set/Clear the read and write protection enable bits of PR register @i
+ * according to @read_prot and @write_prot. */
+static void ich9_set_pr(int i, int read_prot, int write_prot)
+{
+       void *addr = ich_spibar + ICH9_REG_PR0 + (i * 4);
+       uint32_t old = mmio_readl(addr);
+       uint32_t new;
+
+       msg_gspew("PR%u is 0x%08x", i, old);
+       new = old & ~((1 << PR_RP_OFF) | (1 << PR_WP_OFF));
+       if (read_prot)
+               new |= (1 << PR_RP_OFF);
+       if (write_prot)
+               new |= (1 << PR_WP_OFF);
+       if (old == new) {
+               msg_gspew(" already.\n");
+               return;
+       }
+       msg_gspew(", trying to set it to 0x%08x ", new);
+       rmmio_writel(new, addr);
+       msg_gspew("resulted in 0x%08x.\n", mmio_readl(addr));
+}
+
+static const struct spi_programmer spi_programmer_ich7 = {
+       .type = SPI_CONTROLLER_ICH7,
+       .max_data_read = 64,
+       .max_data_write = 64,
+       .command = ich_spi_send_command,
+       .multicommand = ich_spi_send_multicommand,
+       .read = default_spi_read,
+       .write_256 = default_spi_write_256,
+       .write_aai = default_spi_write_aai,
+};
+
+static const struct spi_programmer spi_programmer_ich9 = {
+       .type = SPI_CONTROLLER_ICH9,
+       .max_data_read = 64,
+       .max_data_write = 64,
+       .command = ich_spi_send_command,
+       .multicommand = ich_spi_send_multicommand,
+       .read = default_spi_read,
+       .write_256 = default_spi_write_256,
+       .write_aai = default_spi_write_aai,
+};
+
+static const struct opaque_programmer opaque_programmer_ich_hwseq = {
+       .max_data_read = 64,
+       .max_data_write = 64,
+       .probe = ich_hwseq_probe,
+       .read = ich_hwseq_read,
+       .write = ich_hwseq_write,
+       .erase = ich_hwseq_block_erase,
+};
+
+int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
+                enum ich_chipset ich_gen)
+{
+       int i;
+       uint8_t old, new;
+       uint16_t spibar_offset, tmp2;
+       uint32_t tmp;
+       char *arg;
+       int ich_spi_force = 0;
+       int ich_spi_rw_restricted = 0;
+       int desc_valid = 0;
+       struct ich_descriptors desc = {{ 0 }};
+       enum ich_spi_mode {
+               ich_auto,
+               ich_hwseq,
+               ich_swseq
+       } ich_spi_mode = ich_auto;
+
+       ich_generation = ich_gen;
+
+       switch (ich_generation) {
+       case CHIPSET_ICH_UNKNOWN:
+               return ERROR_FATAL;
+       case CHIPSET_ICH7:
+       case CHIPSET_ICH8:
+               spibar_offset = 0x3020;
+               break;
+       case CHIPSET_ICH9:
+       default:                /* Future version might behave the same */
+               spibar_offset = 0x3800;
+               break;
+       }
+
+       /* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */
+       msg_pdbg("SPIBAR = 0x%x + 0x%04x\n", base, spibar_offset);
+
+       /* Assign Virtual Address */
+       ich_spibar = rcrb + spibar_offset;
+
+       switch (ich_generation) {
+       case CHIPSET_ICH7:
+               msg_pdbg("0x00: 0x%04x     (SPIS)\n",
+                            mmio_readw(ich_spibar + 0));
+               msg_pdbg("0x02: 0x%04x     (SPIC)\n",
+                            mmio_readw(ich_spibar + 2));
+               msg_pdbg("0x04: 0x%08x (SPIA)\n",
+                            mmio_readl(ich_spibar + 4));
+               for (i = 0; i < 8; i++) {
+                       int offs;
+                       offs = 8 + (i * 8);
+                       msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs,
+                                    mmio_readl(ich_spibar + offs), i);
+                       msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
+                                    mmio_readl(ich_spibar + offs + 4), i);
+               }
+               ichspi_bbar = mmio_readl(ich_spibar + 0x50);
+               msg_pdbg("0x50: 0x%08x (BBAR)\n",
+                            ichspi_bbar);
+               msg_pdbg("0x54: 0x%04x     (PREOP)\n",
+                            mmio_readw(ich_spibar + 0x54));
+               msg_pdbg("0x56: 0x%04x     (OPTYPE)\n",
+                            mmio_readw(ich_spibar + 0x56));
+               msg_pdbg("0x58: 0x%08x (OPMENU)\n",
+                            mmio_readl(ich_spibar + 0x58));
+               msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n",
+                            mmio_readl(ich_spibar + 0x5c));
+               for (i = 0; i < 3; i++) {
+                       int offs;
+                       offs = 0x60 + (i * 4);
+                       msg_pdbg("0x%02x: 0x%08x (PBR%d)\n", offs,
+                                    mmio_readl(ich_spibar + offs), i);
+               }
+               if (mmio_readw(ich_spibar) & (1 << 15)) {
+                       msg_pinfo("WARNING: SPI Configuration Lockdown activated.\n");
+                       ichspi_lock = 1;
+               }
+               ich_init_opcodes();
+               ich_set_bbar(0);
+               register_spi_programmer(&spi_programmer_ich7);
+               break;
+       case CHIPSET_ICH8:
+       default:                /* Future version might behave the same */
+               arg = extract_programmer_param("ich_spi_mode");
+               if (arg && !strcmp(arg, "hwseq")) {
+                       ich_spi_mode = ich_hwseq;
+                       msg_pspew("user selected hwseq\n");
+               } else if (arg && !strcmp(arg, "swseq")) {
+                       ich_spi_mode = ich_swseq;
+                       msg_pspew("user selected swseq\n");
+               } else if (arg && !strcmp(arg, "auto")) {
+                       msg_pspew("user selected auto\n");
+                       ich_spi_mode = ich_auto;
+               } else if (arg && !strlen(arg)) {
+                       msg_perr("Missing argument for ich_spi_mode.\n");
+                       free(arg);
+                       return ERROR_FATAL;
+               } else if (arg) {
+                       msg_perr("Unknown argument for ich_spi_mode: %s\n",
+                                arg);
+                       free(arg);
+                       return ERROR_FATAL;
+               }
+               free(arg);
+
+               arg = extract_programmer_param("ich_spi_force");
+               if (arg && !strcmp(arg, "yes")) {
+                       ich_spi_force = 1;
+                       msg_pspew("ich_spi_force enabled.\n");
+               } else if (arg && !strlen(arg)) {
+                       msg_perr("Missing argument for ich_spi_force.\n");
+                       free(arg);
+                       return ERROR_FATAL;
+               } else if (arg) {
+                       msg_perr("Unknown argument for ich_spi_force: \"%s\" "
+                                "(not \"yes\").\n", arg);
+                       free(arg);
+                       return ERROR_FATAL;
+               }
+               free(arg);
+
+               tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFS);
+               msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
+               prettyprint_ich9_reg_hsfs(tmp2);
+               if (tmp2 & HSFS_FLOCKDN) {
+                       msg_pinfo("WARNING: SPI Configuration Lockdown activated.\n");
+                       ichspi_lock = 1;
+               }
+               if (tmp2 & HSFS_FDV)
+                       desc_valid = 1;
+               if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
+                       msg_pinfo("The Flash Descriptor Security Override "
+                                 "Strap-Pin is set. Restrictions implied\n"
+                                 "by the FRAP and FREG registers are NOT in "
+                                 "effect. Please note that Protected\n"
+                                 "Range (PR) restrictions still apply.\n");
+               ich_init_opcodes();
+
+               if (desc_valid) {
+                       tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFC);
+                       msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2);
+                       prettyprint_ich9_reg_hsfc(tmp2);
+               }
+
+               tmp = mmio_readl(ich_spibar + ICH9_REG_FADDR);
+               msg_pdbg("0x08: 0x%08x (FADDR)\n", tmp);
+
+               if (desc_valid) {
+                       tmp = mmio_readl(ich_spibar + ICH9_REG_FRAP);
+                       msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp);
+                       msg_pdbg("BMWAG 0x%02x, ", ICH_BMWAG(tmp));
+                       msg_pdbg("BMRAG 0x%02x, ", ICH_BMRAG(tmp));
+                       msg_pdbg("BRWA 0x%02x, ", ICH_BRWA(tmp));
+                       msg_pdbg("BRRA 0x%02x\n", ICH_BRRA(tmp));
+
+                       /* Handle FREGx and FRAP registers */
+                       for (i = 0; i < 5; i++)
+                               ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
+               }
+
+               for (i = 0; i < 5; i++) {
+                       /* if not locked down try to disable PR locks first */
+                       if (!ichspi_lock)
+                               ich9_set_pr(i, 0, 0);
+                       ich_spi_rw_restricted |= ich9_handle_pr(i);
+               }
+
+               if (ich_spi_rw_restricted) {
+                       msg_pinfo("Please send a verbose log to "
+                                 "flashrom@flashrom.org if this board is not "
+                                 "listed on\n"
+                                 "http://flashrom.org/Supported_hardware#Supported_mainboards "
+                                 "yet.\n");
+                       if (!ich_spi_force)
+                               programmer_may_write = 0;
+                       msg_pinfo("Writes have been disabled. You can enforce "
+                                 "write support with the\nich_spi_force "
+                                 "programmer option, but it will most likely "
+                                 "harm your hardware!\nIf you force flashrom "
+                                 "you will get no support if something "
+                                 "breaks.\n");
+                       if (ich_spi_force)
+                               msg_pinfo("Continuing with write support "
+                                         "because the user forced us to!\n");
+               }
+
+               tmp = mmio_readl(ich_spibar + ICH9_REG_SSFS);
+               msg_pdbg("0x90: 0x%02x (SSFS)\n", tmp & 0xff);
+               prettyprint_ich9_reg_ssfs(tmp);
+               if (tmp & SSFS_FCERR) {
+                       msg_pdbg("Clearing SSFS.FCERR\n");
+                       mmio_writeb(SSFS_FCERR, ich_spibar + ICH9_REG_SSFS);
+               }
+               msg_pdbg("0x91: 0x%06x (SSFC)\n", tmp >> 8);
+               prettyprint_ich9_reg_ssfc(tmp);
+
+               msg_pdbg("0x94: 0x%04x     (PREOP)\n",
+                            mmio_readw(ich_spibar + ICH9_REG_PREOP));
+               msg_pdbg("0x96: 0x%04x     (OPTYPE)\n",
+                            mmio_readw(ich_spibar + ICH9_REG_OPTYPE));
+               msg_pdbg("0x98: 0x%08x (OPMENU)\n",
+                            mmio_readl(ich_spibar + ICH9_REG_OPMENU));
+               msg_pdbg("0x9C: 0x%08x (OPMENU+4)\n",
+                            mmio_readl(ich_spibar + ICH9_REG_OPMENU + 4));
+               if (ich_generation == CHIPSET_ICH8 && desc_valid) {
+                       tmp = mmio_readl(ich_spibar + ICH8_REG_VSCC);
+                       msg_pdbg("0xC1: 0x%08x (VSCC)\n", tmp);
+                       msg_pdbg("VSCC: ");
+                       prettyprint_ich_reg_vscc(tmp, MSG_DEBUG);
+               } else {
+                       ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR);
+                       msg_pdbg("0xA0: 0x%08x (BBAR)\n",
+                                    ichspi_bbar);
+
+                       if (desc_valid) {
+                               tmp = mmio_readl(ich_spibar + ICH9_REG_LVSCC);
+                               msg_pdbg("0xC4: 0x%08x (LVSCC)\n", tmp);
+                               msg_pdbg("LVSCC: ");
+                               prettyprint_ich_reg_vscc(tmp, MSG_DEBUG);
+
+                               tmp = mmio_readl(ich_spibar + ICH9_REG_UVSCC);
+                               msg_pdbg("0xC8: 0x%08x (UVSCC)\n", tmp);
+                               msg_pdbg("UVSCC: ");
+                               prettyprint_ich_reg_vscc(tmp, MSG_DEBUG);
+
+                               tmp = mmio_readl(ich_spibar + ICH9_REG_FPB);
+                               msg_pdbg("0xD0: 0x%08x (FPB)\n", tmp);
+                       }
+                       ich_set_bbar(0);
+               }
+
+               msg_pdbg("\n");
+               if (desc_valid) {
+                       if (read_ich_descriptors_via_fdo(ich_spibar, &desc) ==
+                           ICH_RET_OK)
+                               prettyprint_ich_descriptors(CHIPSET_ICH_UNKNOWN,
+                                                           &desc);
+                       /* If the descriptor is valid and indicates multiple
+                        * flash devices we need to use hwseq to be able to
+                        * access the second flash device.
+                        */
+                       if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
+                               msg_pinfo("Enabling hardware sequencing due to "
+                                         "multiple flash chips detected.\n");
+                               ich_spi_mode = ich_hwseq;
+                       }
+               }
+
+               if (ich_spi_mode == ich_auto && ichspi_lock &&
+                   ich_missing_opcodes()) {
+                       msg_pinfo("Enabling hardware sequencing because "
+                                 "some important opcode is locked.\n");
+                       ich_spi_mode = ich_hwseq;
+               }
+
+               if (ich_spi_mode == ich_hwseq) {
+                       if (!desc_valid) {
+                               msg_perr("Hardware sequencing was requested "
+                                        "but the flash descriptor is not "
+                                        "valid. Aborting.\n");
+                               return ERROR_FATAL;
+                       }
+                       hwseq_data.size_comp0 = getFCBA_component_density(&desc, 0);
+                       hwseq_data.size_comp1 = getFCBA_component_density(&desc, 1);
+                       register_opaque_programmer(&opaque_programmer_ich_hwseq);
+               } else {
+                       register_spi_programmer(&spi_programmer_ich9);
+               }
+               break;
+       }
+
+       old = pci_read_byte(dev, 0xdc);
+       msg_pdbg("SPI Read Configuration: ");
+       new = (old >> 2) & 0x3;
+       switch (new) {
+       case 0:
+       case 1:
+       case 2:
+               msg_pdbg("prefetching %sabled, caching %sabled, ",
+                            (new & 0x2) ? "en" : "dis",
+                            (new & 0x1) ? "dis" : "en");
+               break;
+       default:
+               msg_pdbg("invalid prefetching/caching settings, ");
+               break;
+       }
+       return 0;
+}
+
+static const struct spi_programmer spi_programmer_via = {
+       .type = SPI_CONTROLLER_VIA,
+       .max_data_read = 16,
+       .max_data_write = 16,
+       .command = ich_spi_send_command,
+       .multicommand = ich_spi_send_multicommand,
+       .read = default_spi_read,
+       .write_256 = default_spi_write_256,
+       .write_aai = default_spi_write_aai,
+};
+
+int via_init_spi(struct pci_dev *dev)
+{
+       uint32_t mmio_base;
+       int i;
+
+       mmio_base = (pci_read_long(dev, 0xbc)) << 8;
+       msg_pdbg("MMIO base at = 0x%x\n", mmio_base);
+       ich_spibar = physmap("VT8237S MMIO registers", mmio_base, 0x70);
+
+       /* Not sure if it speaks all these bus protocols. */
+       internal_buses_supported = BUS_LPC | BUS_FWH;
+       ich_generation = CHIPSET_ICH7;
+       register_spi_programmer(&spi_programmer_via);
+
+       msg_pdbg("0x00: 0x%04x     (SPIS)\n", mmio_readw(ich_spibar + 0));
+       msg_pdbg("0x02: 0x%04x     (SPIC)\n", mmio_readw(ich_spibar + 2));
+       msg_pdbg("0x04: 0x%08x (SPIA)\n", mmio_readl(ich_spibar + 4));
+       for (i = 0; i < 2; i++) {
+               int offs;
+               offs = 8 + (i * 8);
+               msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs,
+                        mmio_readl(ich_spibar + offs), i);
+               msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
+                        mmio_readl(ich_spibar + offs + 4), i);
+       }
+       ichspi_bbar = mmio_readl(ich_spibar + 0x50);
+       msg_pdbg("0x50: 0x%08x (BBAR)\n", ichspi_bbar);
+       msg_pdbg("0x54: 0x%04x     (PREOP)\n", mmio_readw(ich_spibar + 0x54));
+       msg_pdbg("0x56: 0x%04x     (OPTYPE)\n", mmio_readw(ich_spibar + 0x56));
+       msg_pdbg("0x58: 0x%08x (OPMENU)\n", mmio_readl(ich_spibar + 0x58));
+       msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n", mmio_readl(ich_spibar + 0x5c));
+       for (i = 0; i < 3; i++) {
+               int offs;
+               offs = 0x60 + (i * 4);
+               msg_pdbg("0x%02x: 0x%08x (PBR%d)\n", offs,
+                        mmio_readl(ich_spibar + offs), i);
+       }
+       msg_pdbg("0x6c: 0x%04x     (CLOCK/DEBUG)\n",
+                mmio_readw(ich_spibar + 0x6c));
+       if (mmio_readw(ich_spibar) & (1 << 15)) {
+               msg_pinfo("WARNING: SPI Configuration Lockdown activated.\n");
+               ichspi_lock = 1;
+       }
+
+       ich_set_bbar(0);
+       ich_init_opcodes();
+
+       return 0;
+}
+
+#endif
diff --git a/internal.c b/internal.c
new file mode 100644 (file)
index 0000000..3ecc348
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * 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; 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 <string.h>
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#if NEED_PCI == 1
+struct pci_dev *pci_dev_find_filter(struct pci_filter filter)
+{
+       struct pci_dev *temp;
+
+       for (temp = pacc->devices; temp; temp = temp->next)
+               if (pci_filter_match(&filter, temp))
+                       return temp;
+
+       return NULL;
+}
+
+struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t devclass)
+{
+       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 == devclass)
+                               return temp;
+               }
+
+       return NULL;
+}
+
+struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
+{
+       struct pci_dev *temp;
+       struct pci_filter filter;
+
+       pci_filter_init(NULL, &filter);
+       filter.vendor = vendor;
+       filter.device = device;
+
+       for (temp = pacc->devices; temp; temp = temp->next)
+               if (pci_filter_match(&filter, temp))
+                       return temp;
+
+       return NULL;
+}
+
+struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
+                             uint16_t card_vendor, uint16_t card_device)
+{
+       struct pci_dev *temp;
+       struct pci_filter filter;
+
+       pci_filter_init(NULL, &filter);
+       filter.vendor = vendor;
+       filter.device = device;
+
+       for (temp = pacc->devices; temp; temp = temp->next)
+               if (pci_filter_match(&filter, temp)) {
+                       if ((card_vendor ==
+                            pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
+                           && (card_device ==
+                               pci_read_word(temp, PCI_SUBSYSTEM_ID)))
+                               return temp;
+               }
+
+       return NULL;
+}
+#endif
+
+#if CONFIG_INTERNAL == 1
+int force_boardenable = 0;
+int force_boardmismatch = 0;
+
+#if defined(__i386__) || defined(__x86_64__)
+void probe_superio(void)
+{
+       probe_superio_winbond();
+       /* ITE probe causes SMSC LPC47N217 to power off the serial UART.
+        * Always probe for SMSC first, and if a SMSC Super I/O is detected
+        * at a given I/O port, do _not_ probe that port with the ITE probe.
+        * This means SMSC probing must be done before ITE probing.
+        */
+       //probe_superio_smsc();
+       probe_superio_ite();
+}
+
+int superio_count = 0;
+#define SUPERIO_MAX_COUNT 3
+
+struct superio superios[SUPERIO_MAX_COUNT];
+
+int register_superio(struct superio s)
+{
+       if (superio_count == SUPERIO_MAX_COUNT)
+               return 1;
+       superios[superio_count++] = s;
+       return 0;
+}
+
+#endif
+
+int is_laptop = 0;
+int laptop_ok = 0;
+
+static void internal_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                chipaddr addr);
+static void internal_chip_writew(const struct flashctx *flash, uint16_t val,
+                                chipaddr addr);
+static void internal_chip_writel(const struct flashctx *flash, uint32_t val,
+                                chipaddr addr);
+static uint8_t internal_chip_readb(const struct flashctx *flash,
+                                  const chipaddr addr);
+static uint16_t internal_chip_readw(const struct flashctx *flash,
+                                   const chipaddr addr);
+static uint32_t internal_chip_readl(const struct flashctx *flash,
+                                   const chipaddr addr);
+static void internal_chip_readn(const struct flashctx *flash, uint8_t *buf,
+                               const chipaddr addr, size_t len);
+static const struct par_programmer par_programmer_internal = {
+               .chip_readb             = internal_chip_readb,
+               .chip_readw             = internal_chip_readw,
+               .chip_readl             = internal_chip_readl,
+               .chip_readn             = internal_chip_readn,
+               .chip_writeb            = internal_chip_writeb,
+               .chip_writew            = internal_chip_writew,
+               .chip_writel            = internal_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+enum chipbustype internal_buses_supported = BUS_NONE;
+
+static int internal_shutdown(void *data)
+{
+       return 0;
+}
+
+int internal_init(void)
+{
+#if __FLASHROM_LITTLE_ENDIAN__
+       int ret = 0;
+#endif
+       int force_laptop = 0;
+       int not_a_laptop = 0;
+       char *arg;
+
+       arg = extract_programmer_param("boardenable");
+       if (arg && !strcmp(arg,"force")) {
+               force_boardenable = 1;
+       } else if (arg && !strlen(arg)) {
+               msg_perr("Missing argument for boardenable.\n");
+               free(arg);
+               return 1;
+       } else if (arg) {
+               msg_perr("Unknown argument for boardenable: %s\n", arg);
+               free(arg);
+               return 1;
+       }
+       free(arg);
+
+       arg = extract_programmer_param("boardmismatch");
+       if (arg && !strcmp(arg,"force")) {
+               force_boardmismatch = 1;
+       } else if (arg && !strlen(arg)) {
+               msg_perr("Missing argument for boardmismatch.\n");
+               free(arg);
+               return 1;
+       } else if (arg) {
+               msg_perr("Unknown argument for boardmismatch: %s\n", arg);
+               free(arg);
+               return 1;
+       }
+       free(arg);
+
+       arg = extract_programmer_param("laptop");
+       if (arg && !strcmp(arg, "force_I_want_a_brick"))
+               force_laptop = 1;
+       else if (arg && !strcmp(arg, "this_is_not_a_laptop"))
+               not_a_laptop = 1;
+       else if (arg && !strlen(arg)) {
+               msg_perr("Missing argument for laptop.\n");
+               free(arg);
+               return 1;
+       } else if (arg) {
+               msg_perr("Unknown argument for laptop: %s\n", arg);
+               free(arg);
+               return 1;
+       }
+       free(arg);
+
+       arg = extract_programmer_param("mainboard");
+       if (arg && strlen(arg)) {
+               lb_vendor_dev_from_string(arg);
+       } else if (arg && !strlen(arg)) {
+               msg_perr("Missing argument for mainboard.\n");
+               free(arg);
+               return 1;
+       }
+       free(arg);
+
+       if (rget_io_perms())
+               return 1;
+       if (register_shutdown(internal_shutdown, NULL))
+               return 1;
+
+       /* Default to Parallel/LPC/FWH flash devices. If a known host controller
+        * is found, the host controller init routine sets the
+        * internal_buses_supported bitfield.
+        */
+       internal_buses_supported = BUS_NONSPI;
+
+       /* Initialize PCI access for flash enables */
+       pacc = pci_alloc();     /* Get the pci_access structure */
+       /* Set all options you want -- here we stick with the defaults */
+       pci_init(pacc);         /* Initialize the PCI library */
+       pci_scan_bus(pacc);     /* We want to get the list of devices */
+
+       if (processor_flash_enable()) {
+               msg_perr("Processor detection/init failed.\n"
+                        "Aborting.\n");
+               return 1;
+       }
+
+#if defined(__i386__) || defined(__x86_64__)
+       /* We look at the cbtable first to see if we need a
+        * mainboard specific flash enable sequence.
+        */
+       coreboot_init();
+
+       dmi_init();
+
+       /* In case Super I/O probing would cause pretty explosions. */
+       board_handle_before_superio();
+
+       /* Probe for the Super I/O chip and fill global struct superio. */
+       probe_superio();
+#else
+       /* FIXME: Enable cbtable searching on all non-x86 platforms supported
+        *        by coreboot.
+        * FIXME: Find a replacement for DMI on non-x86.
+        * FIXME: Enable Super I/O probing once port I/O is possible.
+        */
+#endif
+
+       /* Check laptop whitelist. */
+       board_handle_before_laptop();
+
+       /* Warn if a non-whitelisted laptop is detected. */
+       if (is_laptop && !laptop_ok) {
+               msg_perr("========================================================================\n");
+               if (is_laptop == 1) {
+                       msg_perr("WARNING! You seem to be running flashrom on an unsupported laptop.\n");
+               } else {
+                       msg_perr("WARNING! You may be running flashrom on an unsupported laptop. We could\n"
+                                "not detect this for sure because your vendor has not setup the SMBIOS\n"
+                                "tables correctly. You can enforce execution by adding\n"
+                                "'-p internal:laptop=this_is_not_a_laptop' to the command line, but\n"
+                                "please read the following warning if you are not sure.\n\n");
+               }
+               msg_perr("Laptops, notebooks and netbooks are difficult to support and we\n"
+                        "recommend to use the vendor flashing utility. The embedded controller\n"
+                        "(EC) in these machines often interacts badly with flashing.\n"
+                        "See http://www.flashrom.org/Laptops for details.\n\n"
+                        "If flash is shared with the EC, erase is guaranteed to brick your laptop\n"
+                        "and write may brick your laptop.\n"
+                        "Read and probe may irritate your EC and cause fan failure, backlight\n"
+                        "failure and sudden poweroff.\n"
+                        "You have been warned.\n"
+                        "========================================================================\n");
+
+               if (force_laptop || (not_a_laptop && (is_laptop == 2))) {
+                       msg_perr("Proceeding anyway because user forced us to.\n");
+               } else {
+                       msg_perr("Aborting.\n");
+                       return 1;
+               }
+       }
+
+#if __FLASHROM_LITTLE_ENDIAN__
+       /* try to enable it. Failure IS an option, since not all motherboards
+        * really need this to be done, etc., etc.
+        */
+       ret = chipset_flash_enable();
+       if (ret == -2) {
+               msg_perr("WARNING: No chipset found. Flash detection "
+                        "will most likely fail.\n");
+       } else if (ret == ERROR_FATAL)
+               return ret;
+
+#if defined(__i386__) || defined(__x86_64__)
+       /* Probe unconditionally for IT87* LPC->SPI translation and for
+        * IT87* Parallel write enable.
+        */
+       init_superio_ite();
+#endif
+
+       board_flash_enable(lb_vendor, lb_part);
+
+       /* Even if chipset init returns an error code, we don't want to abort.
+        * The error code might have been a warning only.
+        * Besides that, we don't check the board enable return code either.
+        */
+#if defined(__i386__) || defined(__x86_64__) || defined (__mips)
+       register_par_programmer(&par_programmer_internal, internal_buses_supported);
+       return 0;
+#else
+       msg_perr("Your platform is not supported yet for the internal "
+                "programmer due to missing\n"
+                "flash_base and top/bottom alignment information.\n"
+                "Aborting.\n");
+       return 1;
+#endif
+#else
+       /* FIXME: Remove this unconditional abort once all PCI drivers are
+        * converted to use little-endian accesses for memory BARs.
+        */
+       msg_perr("Your platform is not supported yet for the internal "
+                "programmer because it has\n"
+                "not been converted from native endian to little endian "
+                "access yet.\n"
+                "Aborting.\n");
+       return 1;
+#endif
+}
+#endif
+
+static void internal_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                chipaddr addr)
+{
+       mmio_writeb(val, (void *) addr);
+}
+
+static void internal_chip_writew(const struct flashctx *flash, uint16_t val,
+                                chipaddr addr)
+{
+       mmio_writew(val, (void *) addr);
+}
+
+static void internal_chip_writel(const struct flashctx *flash, uint32_t val,
+                                chipaddr addr)
+{
+       mmio_writel(val, (void *) addr);
+}
+
+static uint8_t internal_chip_readb(const struct flashctx *flash,
+                                  const chipaddr addr)
+{
+       return mmio_readb((void *) addr);
+}
+
+static uint16_t internal_chip_readw(const struct flashctx *flash,
+                                   const chipaddr addr)
+{
+       return mmio_readw((void *) addr);
+}
+
+static uint32_t internal_chip_readl(const struct flashctx *flash,
+                                   const chipaddr addr)
+{
+       return mmio_readl((void *) addr);
+}
+
+static void internal_chip_readn(const struct flashctx *flash, uint8_t *buf,
+                               const chipaddr addr, size_t len)
+{
+       mmio_readn((void *)addr, buf, len);
+       return;
+}
diff --git a/it85spi.c b/it85spi.c
new file mode 100644 (file)
index 0000000..0b074eb
--- /dev/null
+++ b/it85spi.c
@@ -0,0 +1,374 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2008 Ronald Hoogenboom <ronald@zonnet.nl>
+ * Copyright (C) 2008 coresystems GmbH
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 ITE IT85* SPI specific routines
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "flash.h"
+#include "spi.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define MAX_TIMEOUT 100000
+#define MAX_TRY 5
+
+/* Constants for I/O ports */
+#define ITE_SUPERIO_PORT1      0x2e
+#define ITE_SUPERIO_PORT2      0x4e
+
+/* Legacy I/O */
+#define LEGACY_KBC_PORT_DATA   0x60
+#define LEGACY_KBC_PORT_CMD    0x64
+
+/* Constants for Logical Device registers */
+#define LDNSEL                 0x07
+
+/* These are standard Super I/O 16-bit base address registers */
+#define SHM_IO_BAR0            0x60  /* big-endian, this is high bits */
+#define SHM_IO_BAR1            0x61
+
+/* The 8042 keyboard controller uses an input buffer and an output buffer to
+ * communicate with the host CPU. Both buffers are 1-byte depth. That means
+ * IBF is set to 1 when the host CPU sends a command to the input buffer 
+ * of the EC. IBF is cleared to 0 once the command is read by the EC.
+ */
+#define KB_IBF                         (1 << 1)  /* Input Buffer Full */
+#define KB_OBF                         (1 << 0)  /* Output Buffer Full */
+
+/* IT8502 supports two access modes:
+ *   LPC_MEMORY: through the memory window in 0xFFFFFxxx (follow mode)
+ *   LPC_IO: through I/O port (so called indirect memory)
+ */
+#undef LPC_MEMORY
+#define LPC_IO
+
+#ifdef LPC_IO
+/* macro to fill in indirect-access registers. */
+#define INDIRECT_A0(base, value) OUTB(value, (base) + 0)  /* little-endian */
+#define INDIRECT_A1(base, value) OUTB(value, (base) + 1)
+#define INDIRECT_A2(base, value) OUTB(value, (base) + 2)
+#define INDIRECT_A3(base, value) OUTB(value, (base) + 3)
+#define INDIRECT_READ(base) INB((base) + 4)
+#define INDIRECT_WRITE(base, value) OUTB(value, (base) + 4)
+#endif  /* LPC_IO */
+
+#ifdef LPC_IO
+unsigned int shm_io_base;
+#endif
+unsigned char *ce_high, *ce_low;
+static int it85xx_scratch_rom_reenter = 0;
+
+/* This function will poll the keyboard status register until either
+ * an expected value shows up, or the timeout is reached.
+ * timeout is in usec.
+ *
+ * Returns: 0 -- the expected value showed up.
+ *          1 -- timeout.
+ */
+static int wait_for(const unsigned int mask, const unsigned int expected_value,
+                   const int timeout, const char * error_message,
+                   const char * function_name, const int lineno)
+{
+       int time_passed;
+
+       for (time_passed = 0;; ++time_passed) {
+               if ((INB(LEGACY_KBC_PORT_CMD) & mask) == expected_value)
+                       return 0;
+               if (time_passed >= timeout)
+                       break;
+               programmer_delay(1);
+       }
+       if (error_message)
+               msg_perr("%s():%d %s", function_name, lineno, error_message);
+       return 1;
+}
+
+/* IT8502 employs a scratch RAM when flash is being updated. Call the following
+ * two functions before/after flash erase/program. */
+void it85xx_enter_scratch_rom(void)
+{
+       int ret, tries;
+
+       msg_pdbg("%s():%d was called ...\n", __func__, __LINE__);
+       if (it85xx_scratch_rom_reenter > 0)
+               return;
+
+#if 0
+       /* FIXME: this a workaround for the bug that SMBus signal would
+        *        interfere the EC firmware update. Should be removed if
+        *        we find out the root cause. */
+       ret = system("stop powerd >&2");
+       if (ret)
+               msg_perr("Cannot stop powerd.\n");
+#endif
+
+       for (tries = 0; tries < MAX_TRY; ++tries) {
+               /* Wait until IBF (input buffer) is not full. */
+               if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+                            "* timeout at waiting for IBF==0.\n",
+                            __func__, __LINE__))
+                       continue;
+
+               /* Copy EC firmware to SRAM. */
+               OUTB(0xb4, LEGACY_KBC_PORT_CMD);
+
+               /* Confirm EC has taken away the command. */
+               if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+                            "* timeout at taking command.\n",
+                            __func__, __LINE__))
+                       continue;
+
+               /* Waiting for OBF (output buffer) has data.
+                * Note sometimes the replied command might be stolen by kernel
+                * ISR so that it is okay as long as the command is 0xFA. */
+               if (wait_for(KB_OBF, KB_OBF, MAX_TIMEOUT, NULL, NULL, 0))
+                       msg_pdbg("%s():%d * timeout at waiting for OBF.\n",
+                                __func__, __LINE__);
+               if ((ret = INB(LEGACY_KBC_PORT_DATA)) == 0xFA) {
+                       break;
+               } else {
+                       msg_perr("%s():%d * not run on SRAM ret=%d\n",
+                                __func__, __LINE__, ret);
+                       continue;
+               }
+       }
+
+       if (tries < MAX_TRY) {
+               /* EC already runs on SRAM */
+               it85xx_scratch_rom_reenter++;
+               msg_pdbg("%s():%d * SUCCESS.\n", __func__, __LINE__);
+       } else {
+               msg_perr("%s():%d * Max try reached.\n", __func__, __LINE__);
+       }
+}
+
+void it85xx_exit_scratch_rom(void)
+{
+#if 0
+       int ret;
+#endif
+       int tries;
+
+       msg_pdbg("%s():%d was called ...\n", __func__, __LINE__);
+       if (it85xx_scratch_rom_reenter <= 0)
+               return;
+
+       for (tries = 0; tries < MAX_TRY; ++tries) {
+               /* Wait until IBF (input buffer) is not full. */
+               if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+                            "* timeout at waiting for IBF==0.\n",
+                            __func__, __LINE__))
+                       continue;
+
+               /* Exit SRAM. Run on flash. */
+               OUTB(0xFE, LEGACY_KBC_PORT_CMD);
+
+               /* Confirm EC has taken away the command. */
+               if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+                            "* timeout at taking command.\n",
+                            __func__, __LINE__)) {
+                       /* We cannot ensure if EC has exited update mode.
+                        * If EC is in normal mode already, a further 0xFE
+                        * command will reboot system. So, exit loop here. */
+                       tries = MAX_TRY;
+                       break;
+               }
+
+               break;
+       }
+
+       if (tries < MAX_TRY) {
+               it85xx_scratch_rom_reenter = 0;
+               msg_pdbg("%s():%d * SUCCESS.\n", __func__, __LINE__);
+       } else {
+               msg_perr("%s():%d * Max try reached.\n", __func__, __LINE__);
+       }
+
+#if 0
+       /* FIXME: this a workaround for the bug that SMBus signal would
+        *        interfere the EC firmware update. Should be removed if
+        *        we find out the root cause. */
+       ret = system("start powerd >&2");
+       if (ret)
+               msg_perr("Cannot start powerd again.\n");
+#endif
+}
+
+static int it85xx_shutdown(void *data)
+{
+       msg_pdbg("%s():%d\n", __func__, __LINE__);
+       it85xx_exit_scratch_rom();
+
+       return 0;       /* FIXME: Should probably return something meaningful */
+}
+
+static int it85xx_spi_common_init(struct superio s)
+{
+       chipaddr base;
+
+       msg_pdbg("%s():%d superio.vendor=0x%02x\n", __func__, __LINE__,
+                s.vendor);
+
+       if (register_shutdown(it85xx_shutdown, NULL))
+               return 1;
+
+#ifdef LPC_IO
+       /* Get LPCPNP of SHM. That's big-endian. */
+       sio_write(s.port, LDNSEL, 0x0F); /* Set LDN to SHM (0x0F) */
+       shm_io_base = (sio_read(s.port, SHM_IO_BAR0) << 8) +
+                     sio_read(s.port, SHM_IO_BAR1);
+       msg_pdbg("%s():%d shm_io_base=0x%04x\n", __func__, __LINE__,
+                shm_io_base);
+
+       /* These pointers are not used directly. They will be send to EC's
+        * register for indirect access. */
+       base = 0xFFFFF000;
+       ce_high = ((unsigned char *)base) + 0xE00;  /* 0xFFFFFE00 */
+       ce_low = ((unsigned char *)base) + 0xD00;  /* 0xFFFFFD00 */
+
+       /* pre-set indirect-access registers since in most of cases they are
+        * 0xFFFFxx00. */
+       INDIRECT_A0(shm_io_base, base & 0xFF);
+       INDIRECT_A2(shm_io_base, (base >> 16) & 0xFF);
+       INDIRECT_A3(shm_io_base, (base >> 24));
+#endif
+#ifdef LPC_MEMORY
+       /* FIXME: We should block accessing that region for anything else.
+        * Major TODO here, and it will be a lot of work.
+        */
+       base = (chipaddr)physmap("it85 communication", 0xFFFFF000, 0x1000);
+       msg_pdbg("%s():%d base=0x%08x\n", __func__, __LINE__,
+                (unsigned int)base);
+       ce_high = (unsigned char *)(base + 0xE00);  /* 0xFFFFFE00 */
+       ce_low = (unsigned char *)(base + 0xD00);  /* 0xFFFFFD00 */
+#endif
+
+       return 0;
+}
+
+static int it85xx_spi_send_command(struct flashctx *flash,
+                                  unsigned int writecnt, unsigned int readcnt,
+                                  const unsigned char *writearr,
+                                  unsigned char *readarr);
+
+static const struct spi_programmer spi_programmer_it85xx = {
+       .type           = SPI_CONTROLLER_IT85XX,
+       .max_data_read  = 64,
+       .max_data_write = 64,
+       .command        = it85xx_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = default_spi_read,
+       .write_256      = default_spi_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+int it85xx_spi_init(struct superio s)
+{
+       int ret;
+
+       if (!(internal_buses_supported & BUS_FWH)) {
+               msg_pdbg("%s():%d buses not support FWH\n", __func__, __LINE__);
+               return 1;
+       }
+       ret = it85xx_spi_common_init(s);
+       msg_pdbg("FWH: %s():%d ret=%d\n", __func__, __LINE__, ret);
+       if (!ret) {
+               msg_pdbg("%s: internal_buses_supported=0x%x\n", __func__,
+                         internal_buses_supported);
+               /* Check for FWH because IT85 listens to FWH cycles.
+                * FIXME: The big question is whether FWH cycles are necessary
+                * for communication even if LPC_IO is defined.
+                */
+               if (internal_buses_supported & BUS_FWH)
+                       msg_pdbg("Registering IT85 SPI.\n");
+               /* FIXME: Really leave FWH enabled? We can't use this region
+                * anymore since accessing it would mess up IT85 communication.
+                * If we decide to disable FWH for this region, we should print
+                * a debug message about it.
+                */
+               /* Set this as SPI controller. */
+               register_spi_programmer(&spi_programmer_it85xx);
+       }
+       return ret;
+}
+
+/* According to ITE 8502 document, the procedure to follow mode is following:
+ *   1. write 0x00 to LPC/FWH address 0xffff_fexxh (drive CE# high)
+ *   2. write data to LPC/FWH address 0xffff_fdxxh (drive CE# low and MOSI
+ *      with data)
+ *   3. read date from LPC/FWH address 0xffff_fdxxh (drive CE# low and get
+ *      data from MISO)
+ */
+static int it85xx_spi_send_command(struct flashctx *flash,
+                                  unsigned int writecnt, unsigned int readcnt,
+                                  const unsigned char *writearr,
+                                  unsigned char *readarr)
+{
+       int i;
+
+       it85xx_enter_scratch_rom();
+       /* Exit scratch ROM ONLY when programmer shuts down. Otherwise, the
+        * temporary flash state may halt the EC.
+        */
+
+#ifdef LPC_IO
+       INDIRECT_A1(shm_io_base, (((unsigned long int)ce_high) >> 8) & 0xff);
+       INDIRECT_WRITE(shm_io_base, 0xFF);  /* Write anything to this address.*/
+       INDIRECT_A1(shm_io_base, (((unsigned long int)ce_low) >> 8) & 0xff);
+#endif
+#ifdef LPC_MEMORY
+       mmio_writeb(0, ce_high);
+#endif
+       for (i = 0; i < writecnt; ++i) {
+#ifdef LPC_IO
+               INDIRECT_WRITE(shm_io_base, writearr[i]);
+#endif
+#ifdef LPC_MEMORY
+               mmio_writeb(writearr[i], ce_low);
+#endif
+       }
+       for (i = 0; i < readcnt; ++i) {
+#ifdef LPC_IO
+               readarr[i] = INDIRECT_READ(shm_io_base);
+#endif
+#ifdef LPC_MEMORY
+               readarr[i] = mmio_readb(ce_low);
+#endif
+       }
+#ifdef LPC_IO
+       INDIRECT_A1(shm_io_base, (((unsigned long int)ce_high) >> 8) & 0xff);
+       INDIRECT_WRITE(shm_io_base, 0xFF);  /* Write anything to this address.*/
+#endif
+#ifdef LPC_MEMORY
+       mmio_writeb(0, ce_high);
+#endif
+
+       return 0;
+}
+
+#endif
diff --git a/it87spi.c b/it87spi.c
new file mode 100644 (file)
index 0000000..c7bbb13
--- /dev/null
+++ b/it87spi.c
@@ -0,0 +1,410 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2008 Ronald Hoogenboom <ronald@zonnet.nl>
+ * 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 ITE IT87* SPI specific routines
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <string.h>
+#include <stdlib.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "hwaccess.h"
+#include "spi.h"
+
+#define ITE_SUPERIO_PORT1      0x2e
+#define ITE_SUPERIO_PORT2      0x4e
+
+uint16_t it8716f_flashport = 0;
+/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */
+static int fast_spi = 1;
+
+/* Helper functions for most recent ITE IT87xx Super I/O chips */
+#define CHIP_ID_BYTE1_REG      0x20
+#define CHIP_ID_BYTE2_REG      0x21
+#define CHIP_VER_REG           0x22
+void enter_conf_mode_ite(uint16_t port)
+{
+       OUTB(0x87, port);
+       OUTB(0x01, port);
+       OUTB(0x55, port);
+       if (port == ITE_SUPERIO_PORT1)
+               OUTB(0x55, port);
+       else
+               OUTB(0xaa, port);
+}
+
+void exit_conf_mode_ite(uint16_t port)
+{
+       sio_write(port, 0x02, 0x02);
+}
+
+uint16_t probe_id_ite(uint16_t port)
+{
+       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);
+
+       return id;
+}
+
+void probe_superio_ite(void)
+{
+       struct superio s = {};
+       uint16_t ite_ports[] = {ITE_SUPERIO_PORT1, ITE_SUPERIO_PORT2, 0};
+       uint16_t *i = ite_ports;
+
+       s.vendor = SUPERIO_VENDOR_ITE;
+       for (; *i; i++) {
+               s.port = *i;
+               s.model = probe_id_ite(s.port);
+               switch (s.model >> 8) {
+               case 0x82:
+               case 0x86:
+               case 0x87:
+                       /* FIXME: Print revision for all models? */
+                       msg_pdbg("Found ITE Super I/O, ID 0x%04hx on port "
+                                "0x%x\n", s.model, s.port);
+                       register_superio(s);
+                       break;
+               case 0x85:
+                       msg_pdbg("Found ITE EC, ID 0x%04hx,"
+                                "Rev 0x%02x on port 0x%x.\n",
+                                s.model, sio_read(s.port, CHIP_VER_REG),
+                                s.port);
+                       register_superio(s);
+                       break;
+               }
+       }
+
+       return;
+}
+
+static int it8716f_spi_send_command(struct flashctx *flash,
+                                   unsigned int writecnt, unsigned int readcnt,
+                                   const unsigned char *writearr,
+                                   unsigned char *readarr);
+static int it8716f_spi_chip_read(struct flashctx *flash, uint8_t *buf,
+                                unsigned int start, unsigned int len);
+static int it8716f_spi_chip_write_256(struct flashctx *flash, uint8_t *buf,
+                                     unsigned int start, unsigned int len);
+
+static const struct spi_programmer spi_programmer_it87xx = {
+       .type           = SPI_CONTROLLER_IT87XX,
+       .max_data_read  = MAX_DATA_UNSPECIFIED,
+       .max_data_write = MAX_DATA_UNSPECIFIED,
+       .command        = it8716f_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = it8716f_spi_chip_read,
+       .write_256      = it8716f_spi_chip_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+static uint16_t it87spi_probe(uint16_t port)
+{
+       uint8_t tmp = 0;
+       char *portpos = NULL;
+       uint16_t flashport = 0;
+
+       enter_conf_mode_ite(port);
+       /* NOLDN, reg 0x24, mask out lowest bit (suspend) */
+       tmp = sio_read(port, 0x24) & 0xFE;
+       /* Check if LPC->SPI translation is active. */
+       if (!(tmp & 0x0e)) {
+               msg_pdbg("No IT87* serial flash segment enabled.\n");
+               exit_conf_mode_ite(port);
+               /* Nothing to do. */
+               return 0;
+       }
+       msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
+                0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis");
+       msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
+                0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis");
+       msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
+                0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis");
+       msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
+                0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis");
+       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))) {
+               msg_pdbg("Enabling LPC write to serial flash\n");
+               tmp |= 1 << 4;
+               sio_write(port, 0x24, tmp);
+       }
+       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);
+       msg_pdbg("Serial flash port 0x%04x\n", flashport);
+       /* Non-default port requested? */
+       portpos = extract_programmer_param("it87spiport");
+       if (portpos) {
+               char *endptr = NULL;
+               unsigned long forced_flashport;
+               forced_flashport = strtoul(portpos, &endptr, 0);
+               /* Port 0, port >0x1000, unaligned ports and garbage strings
+                * are rejected.
+                */
+               if (!forced_flashport || (forced_flashport >= 0x1000) ||
+                   (forced_flashport & 0x7) || (*endptr != '\0')) {
+                       /* Using ports below 0x100 is a really bad idea, and
+                        * should only be done if no port between 0x100 and
+                        * 0xff8 works due to routing issues.
+                        */
+                       msg_perr("Error: it87spiport specified, but no valid "
+                                "port specified.\nPort must be a multiple of "
+                                "0x8 and lie between 0x100 and 0xff8.\n");
+                       free(portpos);
+                       return 1;
+               } else {
+                       flashport = (uint16_t)forced_flashport;
+                       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);
+       it8716f_flashport = flashport;
+       if (internal_buses_supported & BUS_SPI)
+               msg_pdbg("Overriding chipset SPI with IT87 SPI.\n");
+       /* FIXME: Add the SPI bus or replace the other buses with it? */
+       register_spi_programmer(&spi_programmer_it87xx);
+       return 0;
+}
+
+int init_superio_ite(void)
+{
+       int i;
+       int ret = 0;
+
+       for (i = 0; i < superio_count; i++) {
+               if (superios[i].vendor != SUPERIO_VENDOR_ITE)
+                       continue;
+
+               switch (superios[i].model) {
+               case 0x8500:
+               case 0x8502:
+               case 0x8510:
+               case 0x8511:
+               case 0x8512:
+                       /* FIXME: This should be enabled, but we need a check
+                        * for laptop whitelisting due to the amount of things
+                        * which can go wrong if the EC firmware does not
+                        * implement the interface we want.
+                        */
+                       //it85xx_spi_init(superios[i]);
+                       break;
+               case 0x8705:
+                       ret |= it8705f_write_enable(superios[i].port);
+                       break;
+               case 0x8716:
+               case 0x8718:
+               case 0x8720:
+                       ret |= it87spi_probe(superios[i].port);
+                       break;
+               default:
+                       msg_pdbg("Super I/O ID 0x%04hx is not on the list of "
+                                "flash capable controllers.\n",
+                                superios[i].model);
+               }
+       }
+       return ret;
+}
+
+/*
+ * The IT8716F only supports commands with length 1,2,4,5 bytes including
+ * command byte and can not read more than 3 bytes from the device.
+ *
+ * This function expects writearr[0] to be the first byte sent to the device,
+ * whereas the IT8716F splits commands internally into address and non-address
+ * commands with the address in inverse wire order. That's why the register
+ * ordering in case 4 and 5 may seem strange.
+ */
+static int it8716f_spi_send_command(struct flashctx *flash,
+                                   unsigned int writecnt, unsigned int readcnt,
+                                   const unsigned char *writearr,
+                                   unsigned char *readarr)
+{
+       uint8_t busy, writeenc;
+       int i;
+
+       do {
+               busy = INB(it8716f_flashport) & 0x80;
+       } while (busy);
+       if (readcnt > 3) {
+               msg_pinfo("%s called with unsupported readcnt %i.\n",
+                         __func__, readcnt);
+               return SPI_INVALID_LENGTH;
+       }
+       switch (writecnt) {
+       case 1:
+               OUTB(writearr[0], it8716f_flashport + 1);
+               writeenc = 0x0;
+               break;
+       case 2:
+               OUTB(writearr[0], it8716f_flashport + 1);
+               OUTB(writearr[1], it8716f_flashport + 7);
+               writeenc = 0x1;
+               break;
+       case 4:
+               OUTB(writearr[0], it8716f_flashport + 1);
+               OUTB(writearr[1], it8716f_flashport + 4);
+               OUTB(writearr[2], it8716f_flashport + 3);
+               OUTB(writearr[3], it8716f_flashport + 2);
+               writeenc = 0x2;
+               break;
+       case 5:
+               OUTB(writearr[0], it8716f_flashport + 1);
+               OUTB(writearr[1], it8716f_flashport + 4);
+               OUTB(writearr[2], it8716f_flashport + 3);
+               OUTB(writearr[3], it8716f_flashport + 2);
+               OUTB(writearr[4], it8716f_flashport + 7);
+               writeenc = 0x3;
+               break;
+       default:
+               msg_pinfo("%s called with unsupported writecnt %i.\n",
+                         __func__, writecnt);
+               return SPI_INVALID_LENGTH;
+       }
+       /*
+        * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes.
+        * Note:
+        * We can't use writecnt directly, but have to use a strange encoding.
+        */
+       OUTB(((0x4 + (fast_spi ? 1 : 0)) << 4)
+               | ((readcnt & 0x3) << 2) | (writeenc), it8716f_flashport);
+
+       if (readcnt > 0) {
+               do {
+                       busy = INB(it8716f_flashport) & 0x80;
+               } while (busy);
+
+               for (i = 0; i < readcnt; i++)
+                       readarr[i] = INB(it8716f_flashport + 5 + i);
+       }
+
+       return 0;
+}
+
+/* Page size is usually 256 bytes */
+static int it8716f_spi_page_program(struct flashctx *flash, uint8_t *buf,
+                                   unsigned int start)
+{
+       unsigned int i;
+       int result;
+       chipaddr bios = flash->virtual_memory;
+
+       result = spi_write_enable(flash);
+       if (result)
+               return result;
+       /* FIXME: The command below seems to be redundant or wrong. */
+       OUTB(0x06, it8716f_flashport + 1);
+       OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport);
+       for (i = 0; i < flash->page_size; i++)
+               mmio_writeb(buf[i], (void *)(bios + start + i));
+       OUTB(0, it8716f_flashport);
+       /* Wait until the Write-In-Progress bit is cleared.
+        * This usually takes 1-10 ms, so wait in 1 ms steps.
+        */
+       while (spi_read_status_register(flash) & SPI_SR_WIP)
+               programmer_delay(1000);
+       return 0;
+}
+
+/*
+ * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory cycles
+ * Need to read this big flash using firmware cycles 3 byte at a time.
+ */
+static int it8716f_spi_chip_read(struct flashctx *flash, uint8_t *buf,
+                                unsigned int start, unsigned int len)
+{
+       fast_spi = 0;
+
+       /* FIXME: Check if someone explicitly requested to use IT87 SPI although
+        * the mainboard does not use IT87 SPI translation. This should be done
+        * via a programmer parameter for the internal programmer.
+        */
+       if ((flash->total_size * 1024 > 512 * 1024)) {
+               spi_read_chunked(flash, buf, start, len, 3);
+       } else {
+               mmio_readn((void *)(flash->virtual_memory + start), buf, len);
+       }
+
+       return 0;
+}
+
+static int it8716f_spi_chip_write_256(struct flashctx *flash, uint8_t *buf,
+                                     unsigned int start, unsigned int len)
+{
+       /*
+        * IT8716F only allows maximum of 512 kb SPI chip size for memory
+        * mapped access. It also can't write more than 1+3+256 bytes at once,
+        * so page_size > 256 bytes needs a fallback.
+        * FIXME: Split too big page writes into chunks IT87* can handle instead
+        * of degrading to single-byte program.
+        * FIXME: Check if someone explicitly requested to use IT87 SPI although
+        * the mainboard does not use IT87 SPI translation. This should be done
+        * via a programmer parameter for the internal programmer.
+        */
+       if ((flash->total_size * 1024 > 512 * 1024) ||
+           (flash->page_size > 256)) {
+               spi_chip_write_1(flash, buf, start, len);
+       } else {
+               unsigned int lenhere;
+
+               if (start % flash->page_size) {
+                       /* start to the end of the page or to start + len,
+                        * whichever is smaller.
+                        */
+                       lenhere = min(len, flash->page_size - start % flash->page_size);
+                       spi_chip_write_1(flash, buf, start, lenhere);
+                       start += lenhere;
+                       len -= lenhere;
+                       buf += lenhere;
+               }
+
+               while (len >= flash->page_size) {
+                       it8716f_spi_page_program(flash, buf, start);
+                       start += flash->page_size;
+                       len -= flash->page_size;
+                       buf += flash->page_size;
+               }
+               if (len)
+                       spi_chip_write_1(flash, buf, start, len);
+       }
+
+       return 0;
+}
+
+#endif
diff --git a/jedec.c b/jedec.c
new file mode 100644 (file)
index 0000000..69c0c0c
--- /dev/null
+++ b/jedec.c
@@ -0,0 +1,513 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
+ * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
+ * Copyright (C) 2007 Carl-Daniel Hailfinger
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.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)
+{
+       val = (val ^ (val >> 4)) & 0xf;
+       val = (val ^ (val >> 2)) & 0x3;
+       return (val ^ (val >> 1)) & 0x1;
+}
+
+static void toggle_ready_jedec_common(const struct flashctx *flash,
+                                     chipaddr dst, int delay)
+{
+       unsigned int i = 0;
+       uint8_t tmp1, tmp2;
+
+       tmp1 = chip_readb(flash, dst) & 0x40;
+
+       while (i++ < 0xFFFFFFF) {
+               if (delay)
+                       programmer_delay(delay);
+               tmp2 = chip_readb(flash, 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(const struct flashctx *flash, chipaddr dst)
+{
+       toggle_ready_jedec_common(flash, 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.
+ */
+static void toggle_ready_jedec_slow(const struct flashctx *flash, chipaddr dst)
+{
+       toggle_ready_jedec_common(flash, dst, 8 * 1000);
+}
+
+void data_polling_jedec(const struct flashctx *flash, chipaddr dst,
+                       uint8_t data)
+{
+       unsigned int i = 0;
+       uint8_t tmp;
+
+       data &= 0x80;
+
+       while (i++ < 0xFFFFFFF) {
+               tmp = chip_readb(flash, dst) & 0x80;
+               if (tmp == data) {
+                       break;
+               }
+       }
+       if (i > 0x100000)
+               msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
+}
+
+static unsigned int getaddrmask(struct flashctx *flash)
+{
+       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;
+       }
+}
+
+static void start_program_jedec_common(struct flashctx *flash,
+                                      unsigned int mask)
+{
+       chipaddr bios = flash->virtual_memory;
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       chip_writeb(flash, 0xA0, bios + (0x5555 & mask));
+}
+
+static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t id1, id2;
+       uint32_t largeid1, largeid2;
+       uint32_t flashcontent1, flashcontent2;
+       int probe_timing_enter, probe_timing_exit;
+
+       if (flash->probe_timing > 0) 
+               probe_timing_enter = probe_timing_exit = flash->probe_timing;
+       else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */
+               probe_timing_enter = probe_timing_exit = 0;
+       } else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */
+               msg_cdbg("Chip lacks correct probe timing information, "
+                            "using default 10mS/40uS. ");
+               probe_timing_enter = 10000;
+               probe_timing_exit = 40;
+       } else {
+               msg_cerr("Chip has negative value in probe_timing, failing "
+                      "without chip access\n");
+               return 0;
+       }
+
+       /* Earlier probes might have been too fast for the chip to enter ID
+        * mode completely. Allow the chip to finish this before seeing a
+        * reset command.
+        */
+       if (probe_timing_enter)
+               programmer_delay(probe_timing_enter);
+       /* Reset chip to a clean slate */
+       if ((flash->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+       {
+               chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+               if (probe_timing_exit)
+                       programmer_delay(10);
+               chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+               if (probe_timing_exit)
+                       programmer_delay(10);
+       }
+       chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+       if (probe_timing_exit)
+               programmer_delay(probe_timing_exit);
+
+       /* Issue JEDEC Product ID Entry command */
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       if (probe_timing_enter)
+               programmer_delay(10);
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       if (probe_timing_enter)
+               programmer_delay(10);
+       chip_writeb(flash, 0x90, bios + (0x5555 & mask));
+       if (probe_timing_enter)
+               programmer_delay(probe_timing_enter);
+
+       /* Read product ID */
+       id1 = chip_readb(flash, bios);
+       id2 = chip_readb(flash, 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(flash, bios + 0x100);
+               largeid1 |= id1;
+       }
+       if (id2 == 0x7F) {
+               largeid2 <<= 8;
+               id2 = chip_readb(flash, bios + 0x101);
+               largeid2 |= id2;
+       }
+
+       /* Issue JEDEC Product ID Exit command */
+       if ((flash->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+       {
+               chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+               if (probe_timing_exit)
+                       programmer_delay(10);
+               chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+               if (probe_timing_exit)
+                       programmer_delay(10);
+       }
+       chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+       if (probe_timing_exit)
+               programmer_delay(probe_timing_exit);
+
+       msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
+       if (!oddparity(id1))
+               msg_cdbg(", id1 parity violation");
+
+       /* Read the product ID location again. We should now see normal flash contents. */
+       flashcontent1 = chip_readb(flash, bios);
+       flashcontent2 = chip_readb(flash, bios + 0x01);
+
+       /* Check if it is a continuation ID, this should be a while loop. */
+       if (flashcontent1 == 0x7F) {
+               flashcontent1 <<= 8;
+               flashcontent1 |= chip_readb(flash, bios + 0x100);
+       }
+       if (flashcontent2 == 0x7F) {
+               flashcontent2 <<= 8;
+               flashcontent2 |= chip_readb(flash, bios + 0x101);
+       }
+
+       if (largeid1 == flashcontent1)
+               msg_cdbg(", id1 is normal flash content");
+       if (largeid2 == flashcontent2)
+               msg_cdbg(", id2 is normal flash content");
+
+       msg_cdbg("\n");
+       if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id)
+               return 0;
+
+       if (flash->feature_bits & FEATURE_REGISTERMAP)
+               map_flash_registers(flash);
+
+       return 1;
+}
+
+static int erase_sector_jedec_common(struct flashctx *flash, unsigned int page,
+                                    unsigned int pagesize, unsigned int mask)
+{
+       chipaddr bios = flash->virtual_memory;
+       int delay_us = 0;
+       if(flash->probe_timing != TIMING_ZERO)
+               delay_us = 10;
+
+       /*  Issue the Sector Erase command   */
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x80, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x30, bios + page);
+       programmer_delay(delay_us);
+
+       /* wait for Toggle bit ready         */
+       toggle_ready_jedec_slow(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+static int erase_block_jedec_common(struct flashctx *flash, unsigned int block,
+                                   unsigned int blocksize, unsigned int mask)
+{
+       chipaddr bios = flash->virtual_memory;
+       int delay_us = 0;
+       if(flash->probe_timing != TIMING_ZERO)
+               delay_us = 10;
+
+       /*  Issue the Sector Erase command   */
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x80, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x50, bios + block);
+       programmer_delay(delay_us);
+
+       /* wait for Toggle bit ready         */
+       toggle_ready_jedec_slow(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+static int erase_chip_jedec_common(struct flashctx *flash, unsigned int mask)
+{
+       chipaddr bios = flash->virtual_memory;
+       int delay_us = 0;
+       if(flash->probe_timing != TIMING_ZERO)
+               delay_us = 10;
+
+       /*  Issue the JEDEC Chip Erase command   */
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x80, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+
+       chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+       programmer_delay(delay_us);
+       chip_writeb(flash, 0x10, bios + (0x5555 & mask));
+       programmer_delay(delay_us);
+
+       toggle_ready_jedec_slow(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+static int write_byte_program_jedec_common(struct flashctx *flash, uint8_t *src,
+                                          chipaddr dst, unsigned int mask)
+{
+       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(flash, *src, dst);
+       toggle_ready_jedec(flash, bios);
+
+       if (chip_readb(flash, dst) != *src && tried++ < MAX_REFLASH_TRIES) {
+               goto retry;
+       }
+
+       if (tried >= MAX_REFLASH_TRIES)
+               failed = 1;
+
+       return failed;
+}
+
+/* chunksize is 1 */
+int write_jedec_1(struct flashctx *flash, uint8_t *src, unsigned int start,
+                 unsigned int len)
+{
+       int i, failed = 0;
+       chipaddr dst = flash->virtual_memory + start;
+       chipaddr olddst;
+       unsigned int mask;
+
+       mask = getaddrmask(flash);
+
+       olddst = dst;
+       for (i = 0; i < len; 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 flashctx *flash, uint8_t *src,
+                                 unsigned int start, unsigned int page_size)
+{
+       int i, tried = 0, failed;
+       uint8_t *s = src;
+       chipaddr bios = flash->virtual_memory;
+       chipaddr dst = bios + start;
+       chipaddr d = dst;
+       unsigned int mask;
+
+       mask = getaddrmask(flash);
+
+retry:
+       /* Issue JEDEC Start Program command */
+       start_program_jedec_common(flash, mask);
+
+       /* transfer data from source to destination */
+       for (i = 0; i < page_size; i++) {
+               /* If the data is 0xFF, don't program it */
+               if (*src != 0xFF)
+                       chip_writeb(flash, *src, dst);
+               dst++;
+               src++;
+       }
+
+       toggle_ready_jedec(flash, dst - 1);
+
+       dst = d;
+       src = s;
+       failed = verify_range(flash, src, start, page_size, NULL);
+
+       if (failed && tried++ < MAX_REFLASH_TRIES) {
+               msg_cerr("retrying.\n");
+               goto retry;
+       }
+       if (failed) {
+               msg_cerr(" page 0x%lx failed!\n",
+                       (d - bios) / page_size);
+       }
+       return failed;
+}
+
+/* chunksize is page_size */
+/*
+ * Write a part of the flash chip.
+ * FIXME: Use the chunk code from Michael Karcher instead.
+ * This function is a slightly modified copy of spi_write_chunked.
+ * Each page is written separately in chunks with a maximum size of chunksize.
+ */
+int write_jedec(struct flashctx *flash, uint8_t *buf, unsigned int start,
+               int unsigned len)
+{
+       unsigned int i, starthere, lenhere;
+       /* FIXME: page_size is the wrong variable. We need max_writechunk_size
+        * in struct flashctx to do this properly. All chips using
+        * write_jedec have page_size set to max_writechunk_size, so
+        * we're OK for now.
+        */
+       unsigned int page_size = flash->page_size;
+
+       /* 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;
+
+               if (write_page_write_jedec_common(flash, buf + starthere - start, starthere, lenhere))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/* erase chip with block_erase() prototype */
+int erase_chip_block_jedec(struct flashctx *flash, unsigned int addr,
+                          unsigned int blocksize)
+{
+       unsigned int mask;
+
+       mask = getaddrmask(flash);
+       if ((addr != 0) || (blocksize != flash->total_size * 1024)) {
+               msg_cerr("%s called with incorrect arguments\n",
+                       __func__);
+               return -1;
+       }
+       return erase_chip_jedec_common(flash, mask);
+}
+
+int probe_jedec(struct flashctx *flash)
+{
+       unsigned int mask;
+
+       mask = getaddrmask(flash);
+       return probe_jedec_common(flash, mask);
+}
+
+int erase_sector_jedec(struct flashctx *flash, unsigned int page,
+                      unsigned int size)
+{
+       unsigned int mask;
+
+       mask = getaddrmask(flash);
+       return erase_sector_jedec_common(flash, page, size, mask);
+}
+
+int erase_block_jedec(struct flashctx *flash, unsigned int page,
+                     unsigned int size)
+{
+       unsigned int mask;
+
+       mask = getaddrmask(flash);
+       return erase_block_jedec_common(flash, page, size, mask);
+}
+
+int erase_chip_jedec(struct flashctx *flash)
+{
+       unsigned int mask;
+
+       mask = getaddrmask(flash);
+       return erase_chip_jedec_common(flash, mask);
+}
diff --git a/layout.c b/layout.c
new file mode 100644 (file)
index 0000000..0512638
--- /dev/null
+++ b/layout.c
@@ -0,0 +1,355 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2005-2008 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan@coresystems.de> for 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include "flash.h"
+#include "programmer.h"
+
+#if CONFIG_INTERNAL == 1
+char *mainboard_vendor = NULL;
+char *mainboard_part = NULL;
+#endif
+static int romimages = 0;
+
+#define MAX_ROMLAYOUT  32
+
+typedef struct {
+       unsigned int start;
+       unsigned int end;
+       unsigned int included;
+       char name[256];
+} romlayout_t;
+
+/* include_args lists arguments specified at the command line with -i. They
+ * must be processed at some point so that desired regions are marked as
+ * "included" in the rom_entries list.
+ */
+static char *include_args[MAX_ROMLAYOUT];
+static int num_include_args = 0; /* the number of valid entries. */
+static romlayout_t rom_entries[MAX_ROMLAYOUT];
+
+#if CONFIG_INTERNAL == 1 /* FIXME: Move the whole block to cbtable.c? */
+static char *def_name = "DEFAULT";
+
+int show_id(uint8_t *bios, int size, int force)
+{
+       unsigned int *walk;
+       unsigned int mb_part_offset, mb_vendor_offset;
+       char *mb_part, *mb_vendor;
+
+       mainboard_vendor = def_name;
+       mainboard_part = def_name;
+
+       walk = (unsigned int *)(bios + size - 0x10);
+       walk--;
+
+       if ((*walk) == 0 || ((*walk) & 0x3ff) != 0) {
+               /* We might have an NVIDIA chipset BIOS which stores the ID
+                * information at a different location.
+                */
+               walk = (unsigned int *)(bios + size - 0x80);
+               walk--;
+       }
+
+       /*
+        * Check if coreboot last image size is 0 or not a multiple of 1k or
+        * bigger than the chip or if the pointers to vendor ID or mainboard ID
+        * are outside the image of if the start of ID strings are nonsensical
+        * (nonprintable and not \0).
+        */
+       mb_part_offset = *(walk - 1);
+       mb_vendor_offset = *(walk - 2);
+       if ((*walk) == 0 || ((*walk) & 0x3ff) != 0 || (*walk) > size ||
+           mb_part_offset > size || mb_vendor_offset > size) {
+               msg_pinfo("Flash image seems to be a legacy BIOS. "
+                         "Disabling coreboot-related checks.\n");
+               return 0;
+       }
+
+       mb_part = (char *)(bios + size - mb_part_offset);
+       mb_vendor = (char *)(bios + size - mb_vendor_offset);
+       if (!isprint((unsigned char)*mb_part) ||
+           !isprint((unsigned char)*mb_vendor)) {
+               msg_pinfo("Flash image seems to have garbage in the ID location."
+                      " Disabling checks.\n");
+               return 0;
+       }
+
+       msg_pdbg("coreboot last image size "
+                    "(not ROM size) is %d bytes.\n", *walk);
+
+       mainboard_part = strdup(mb_part);
+       mainboard_vendor = strdup(mb_vendor);
+       msg_pdbg("Manufacturer: %s\n", mainboard_vendor);
+       msg_pdbg("Mainboard ID: %s\n", mainboard_part);
+
+       /*
+        * If lb_vendor is not set, the coreboot table was
+        * not found. Nor was -p internal:mainboard=VENDOR:PART specified.
+        */
+       if (!lb_vendor || !lb_part) {
+               msg_pinfo("Note: If the following flash access fails, try "
+                         "-p internal:mainboard=<vendor>:<mainboard>.\n");
+               return 0;
+       }
+
+       /* These comparisons are case insensitive to make things
+        * a little less user^Werror prone. 
+        */
+       if (!strcasecmp(mainboard_vendor, lb_vendor) &&
+           !strcasecmp(mainboard_part, lb_part)) {
+               msg_pdbg("This firmware image matches this mainboard.\n");
+       } else {
+               if (force_boardmismatch) {
+                       msg_pinfo("WARNING: This firmware image does not "
+                              "seem to fit to this machine - forcing it.\n");
+               } else {
+                       msg_pinfo("ERROR: Your firmware image (%s:%s) does not "
+                                 "appear to\n"
+                                 "       be correct for the detected "
+                                 "mainboard (%s:%s)\n\n"
+                                 "Override with -p internal:boardmismatch="
+                                 "force to ignore the board name in the\n"
+                                 "firmware image or override the detected "
+                                 "mainboard with\n"
+                                 "-p internal:mainboard=<vendor>:<mainboard>."
+                                 "\n\n",
+                                 mainboard_vendor, mainboard_part, lb_vendor,
+                                 lb_part);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+#endif
+
+#ifndef __LIBPAYLOAD__
+int read_romlayout(char *name)
+{
+       FILE *romlayout;
+       char tempstr[256];
+       int i;
+
+       romlayout = fopen(name, "r");
+
+       if (!romlayout) {
+               msg_gerr("ERROR: Could not open ROM layout (%s).\n",
+                       name);
+               return -1;
+       }
+
+       while (!feof(romlayout)) {
+               char *tstr1, *tstr2;
+
+               if (romimages >= MAX_ROMLAYOUT) {
+                       msg_gerr("Maximum number of ROM images (%i) in layout "
+                                "file reached.\n", MAX_ROMLAYOUT);
+                       return 1;
+               }
+               if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[romimages].name))
+                       continue;
+#if 0
+               // fscanf does not like arbitrary comments like that :( later
+               if (tempstr[0] == '#') {
+                       continue;
+               }
+#endif
+               tstr1 = strtok(tempstr, ":");
+               tstr2 = strtok(NULL, ":");
+               if (!tstr1 || !tstr2) {
+                       msg_gerr("Error parsing layout file.\n");
+                       fclose(romlayout);
+                       return 1;
+               }
+               rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16);
+               rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16);
+               rom_entries[romimages].included = 0;
+               romimages++;
+       }
+
+       for (i = 0; i < romimages; i++) {
+               msg_gdbg("romlayout %08x - %08x named %s\n",
+                            rom_entries[i].start,
+                            rom_entries[i].end, rom_entries[i].name);
+       }
+
+       fclose(romlayout);
+
+       return 0;
+}
+#endif
+
+/* returns the index of the entry (or a negative value if it is not found) */
+int find_include_arg(const char *const name)
+{
+       unsigned int i;
+       for (i = 0; i < num_include_args; i++) {
+               if (!strcmp(include_args[i], name))
+                       return i;
+       }
+       return -1;
+}
+
+/* register an include argument (-i) for later processing */
+int register_include_arg(char *name)
+{
+       if (num_include_args >= MAX_ROMLAYOUT) {
+               msg_gerr("Too many regions included (%i).\n", num_include_args);
+               return 1;
+       }
+
+       if (name == NULL) {
+               msg_gerr("<NULL> is a bad region name.\n");
+               return 1;
+       }
+
+       if (find_include_arg(name) != -1) {
+               msg_gerr("Duplicate region name: \"%s\".\n", name);
+               return 1;
+       }
+
+       include_args[num_include_args] = name;
+       num_include_args++;
+       return 0;
+}
+
+/* returns the index of the entry (or a negative value if it is not found) */
+static int find_romentry(char *name)
+{
+       int i;
+
+       if (!romimages)
+               return -1;
+
+       msg_gspew("Looking for region \"%s\"... ", name);
+       for (i = 0; i < romimages; i++) {
+               if (!strcmp(rom_entries[i].name, name)) {
+                       rom_entries[i].included = 1;
+                       msg_gspew("found.\n");
+                       return i;
+               }
+       }
+       msg_gspew("not found.\n");
+       return -1;
+}
+
+/* process -i arguments
+ * returns 0 to indicate success, >0 to indicate failure
+ */
+int process_include_args(void)
+{
+       int i;
+       unsigned int found = 0;
+
+       if (num_include_args == 0)
+               return 0;
+
+       /* User has specified an area, but no layout file is loaded. */
+       if (!romimages) {
+               msg_gerr("Region requested (with -i \"%s\"), "
+                        "but no layout data is available.\n",
+                        include_args[0]);
+               return 1;
+       }
+
+       for (i = 0; i < num_include_args; i++) {
+               if (find_romentry(include_args[i]) < 0) {
+                       msg_gerr("Invalid region specified: \"%s\".\n",
+                                include_args[i]);
+                       return 1;
+               }
+               found++;
+       }
+
+       msg_ginfo("Using region%s: \"%s\"", num_include_args > 1 ? "s" : "",
+                 include_args[0]);
+       for (i = 1; i < num_include_args; i++)
+               msg_ginfo(", \"%s\"", include_args[i]);
+       msg_ginfo(".\n");
+       return 0;
+}
+
+romlayout_t *get_next_included_romentry(unsigned int start)
+{
+       int i;
+       unsigned int best_start = UINT_MAX;
+       romlayout_t *best_entry = NULL;
+       romlayout_t *cur;
+
+       /* First come, first serve for overlapping regions. */
+       for (i = 0; i < romimages; i++) {
+               cur = &rom_entries[i];
+               if (!cur->included)
+                       continue;
+               /* Already past the current entry? */
+               if (start > cur->end)
+                       continue;
+               /* Inside the current entry? */
+               if (start >= cur->start)
+                       return cur;
+               /* Entry begins after start. */
+               if (best_start > cur->start) {
+                       best_start = cur->start;
+                       best_entry = cur;
+               }
+       }
+       return best_entry;
+}
+
+int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents)
+{
+       unsigned int start = 0;
+       romlayout_t *entry;
+       unsigned int size = flash->total_size * 1024;
+
+       /* If no regions were specified for inclusion, assume
+        * that the user wants to write the complete new image.
+        */
+       if (num_include_args == 0)
+               return 0;
+
+       /* Non-included romentries are ignored.
+        * The union of all included romentries is used from the new image.
+        */
+       while (start < size) {
+               entry = get_next_included_romentry(start);
+               /* No more romentries for remaining region? */
+               if (!entry) {
+                       memcpy(newcontents + start, oldcontents + start,
+                              size - start);
+                       break;
+               }
+               /* For non-included region, copy from old content. */
+               if (entry->start > start)
+                       memcpy(newcontents + start, oldcontents + start,
+                              entry->start - start);
+               /* Skip to location after current romentry. */
+               start = entry->end + 1;
+               /* Catch overflow. */
+               if (!start)
+                       break;
+       }
+       return 0;
+}
diff --git a/linux_spi.c b/linux_spi.c
new file mode 100644 (file)
index 0000000..2f46463
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011 Sven Schnelle <svens@stackframe.org>
+ *
+ * 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
+ */
+
+#if CONFIG_LINUX_SPI == 1
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+#include <sys/ioctl.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "spi.h"
+
+static int fd = -1;
+
+static int linux_spi_shutdown(void *data);
+static int linux_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                                 unsigned int readcnt,
+                                 const unsigned char *txbuf,
+                                 unsigned char *rxbuf);
+static int linux_spi_read(struct flashctx *flash, uint8_t *buf,
+                         unsigned int start, unsigned int len);
+static int linux_spi_write_256(struct flashctx *flash, uint8_t *buf,
+                              unsigned int start, unsigned int len);
+
+static const struct spi_programmer spi_programmer_linux = {
+       .type           = SPI_CONTROLLER_LINUX,
+       .max_data_read  = MAX_DATA_UNSPECIFIED, /* TODO? */
+       .max_data_write = MAX_DATA_UNSPECIFIED, /* TODO? */
+       .command        = linux_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = linux_spi_read,
+       .write_256      = linux_spi_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+int linux_spi_init(void)
+{
+       char *p, *endp, *dev;
+       uint32_t speed = 0;
+       /* FIXME: make the following configurable by CLI options. */
+       /* SPI mode 0 (beware this also includes: MSB first, CS active low and others */
+       const uint8_t mode = SPI_MODE_0;
+       const uint8_t bits = 8;
+
+       dev = extract_programmer_param("dev");
+       if (!dev || !strlen(dev)) {
+               msg_perr("No SPI device given. Use flashrom -p "
+                        "linux_spi:dev=/dev/spidevX.Y\n");
+               return 1;
+       }
+
+       p = extract_programmer_param("speed");
+       if (p && strlen(p)) {
+               speed = (uint32_t)strtoul(p, &endp, 10) * 1024;
+               if (p == endp) {
+                       msg_perr("%s: invalid clock: %s kHz\n", __func__, p);
+                       return 1;
+               }
+       }
+
+       msg_pdbg("Using device %s\n", dev);
+       if ((fd = open(dev, O_RDWR)) == -1) {
+               msg_perr("%s: failed to open %s: %s\n", __func__,
+                        dev, strerror(errno));
+               return 1;
+       }
+
+       if (register_shutdown(linux_spi_shutdown, NULL))
+               return 1;
+       /* We rely on the shutdown function for cleanup from here on. */
+
+       if (speed > 0) {
+               if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
+                       msg_perr("%s: failed to set speed to %d Hz: %s\n",
+                                __func__, speed, strerror(errno));
+                       return 1;
+               }
+
+               msg_pdbg("Using %d kHz clock\n", speed);
+       }
+
+       if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
+               msg_perr("%s: failed to set SPI mode to 0x%02x: %s\n",
+                        __func__, mode, strerror(errno));
+               return 1;
+       }
+
+       if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) {
+               msg_perr("%s: failed to set the number of bits per SPI word to %u: %s\n",
+                        __func__, bits == 0 ? 8 : bits, strerror(errno));
+               return 1;
+       }
+
+       register_spi_programmer(&spi_programmer_linux);
+
+       return 0;
+}
+
+static int linux_spi_shutdown(void *data)
+{
+       if (fd != -1) {
+               close(fd);
+               fd = -1;
+       }
+       return 0;
+}
+
+static int linux_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                                 unsigned int readcnt,
+                                 const unsigned char *txbuf,
+                                 unsigned char *rxbuf)
+{
+       int iocontrol_code;
+       struct spi_ioc_transfer msg[2] = {
+               {
+                       .tx_buf = (uint64_t)(ptrdiff_t)txbuf,
+                       .len = writecnt,
+               },
+               {
+                       .rx_buf = (uint64_t)(ptrdiff_t)rxbuf,
+                       .len = readcnt,
+               },
+       };
+
+       if (fd == -1)
+               return -1;
+       /* The implementation currently does not support requests that
+          don't start with sending a command. */
+       if (writecnt == 0)
+               return SPI_INVALID_LENGTH;
+
+       /* Just submit the first (write) request in case there is nothing
+          to read. Otherwise submit both requests. */
+       if (readcnt == 0)
+               iocontrol_code = SPI_IOC_MESSAGE(1);
+       else
+               iocontrol_code = SPI_IOC_MESSAGE(2);
+
+       if (ioctl(fd, iocontrol_code, msg) == -1) {
+               msg_cerr("%s: ioctl: %s\n", __func__, strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+
+static int linux_spi_read(struct flashctx *flash, uint8_t *buf,
+                         unsigned int start, unsigned int len)
+{
+       return spi_read_chunked(flash, buf, start, len,
+                               (unsigned int)getpagesize());
+}
+
+static int linux_spi_write_256(struct flashctx *flash, uint8_t *buf,
+                              unsigned int start, unsigned int len)
+{
+       return spi_write_chunked(flash, buf, start, len,
+                               ((unsigned int)getpagesize()) - 4);
+}
+
+#endif // CONFIG_LINUX_SPI == 1
diff --git a/m29f400bt.c b/m29f400bt.c
new file mode 100644 (file)
index 0000000..c9d8a40
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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"
+#include "chipdrivers.h"
+
+/* 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. */
+
+/* chunksize is 1 */
+int write_m29f400bt(struct flashctx *flash, uint8_t *src, unsigned int start,
+                   unsigned int len)
+{
+       int i;
+       chipaddr bios = flash->virtual_memory;
+       chipaddr dst = flash->virtual_memory + start;
+
+       for (i = 0; i < len; i++) {
+               chip_writeb(flash, 0xAA, bios + 0xAAA);
+               chip_writeb(flash, 0x55, bios + 0x555);
+               chip_writeb(flash, 0xA0, bios + 0xAAA);
+
+               /* transfer data from source to destination */
+               chip_writeb(flash, *src, dst);
+               toggle_ready_jedec(flash, dst);
+#if 0
+               /* We only want to print something in the error case. */
+               msg_cerr("Value in the flash at address 0x%lx = %#x, want %#x\n",
+                    (dst - bios), chip_readb(flash, dst), *src);
+#endif
+               dst++;
+               src++;
+       }
+
+       /* FIXME: Ignore errors for now. */
+       return 0;
+}
+
+int probe_m29f400bt(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t id1, id2;
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x90, bios + 0xAAA);
+
+       programmer_delay(10);
+
+       id1 = chip_readb(flash, bios);
+       /* The data sheet says id2 is at (bios + 0x01) and id2 listed in
+        * flash.h does not match. It should be possible to use JEDEC probe.
+        */
+       id2 = chip_readb(flash, bios + 0x02);
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0xF0, bios + 0xAAA);
+
+       programmer_delay(10);
+
+       msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+       if (id1 == flash->manufacture_id && id2 == flash->model_id)
+               return 1;
+
+       return 0;
+}
+
+int erase_m29f400bt(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x80, bios + 0xAAA);
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x10, bios + 0xAAA);
+
+       programmer_delay(10);
+       toggle_ready_jedec(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int block_erase_m29f400bt(struct flashctx *flash, unsigned int start,
+                         unsigned int len)
+{
+       chipaddr bios = flash->virtual_memory;
+       chipaddr dst = bios + start;
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x80, bios + 0xAAA);
+
+       chip_writeb(flash, 0xAA, bios + 0xAAA);
+       chip_writeb(flash, 0x55, bios + 0x555);
+       chip_writeb(flash, 0x30, dst);
+
+       programmer_delay(10);
+       toggle_ready_jedec(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int block_erase_chip_m29f400bt(struct flashctx *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);
+}
diff --git a/mcp6x_spi.c b/mcp6x_spi.c
new file mode 100644 (file)
index 0000000..ac40557
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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
+ */
+
+/* Driver for the NVIDIA MCP6x/MCP7x MCP6X_SPI controller.
+ * Based on clean room reverse engineered docs from
+ * http://www.flashrom.org/pipermail/flashrom/2009-December/001180.html
+ * created by Michael Karcher.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdlib.h>
+#include <ctype.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+/* Bit positions for each pin. */
+
+#define MCP6X_SPI_CS           1
+#define MCP6X_SPI_SCK          2
+#define MCP6X_SPI_MOSI         3
+#define MCP6X_SPI_MISO         4
+#define MCP6X_SPI_REQUEST      0
+#define MCP6X_SPI_GRANT                8
+
+void *mcp6x_spibar = NULL;
+
+/* Cached value of last GPIO state. */
+static uint8_t mcp_gpiostate;
+
+static void mcp6x_request_spibus(void)
+{
+       mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
+       mcp_gpiostate |= 1 << MCP6X_SPI_REQUEST;
+       mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+
+       /* Wait until we are allowed to use the SPI bus. */
+       while (!(mmio_readw(mcp6x_spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) ;
+
+       /* Update the cache. */
+       mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
+}
+
+static void mcp6x_release_spibus(void)
+{
+       mcp_gpiostate &= ~(1 << MCP6X_SPI_REQUEST);
+       mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+}
+
+static void mcp6x_bitbang_set_cs(int val)
+{
+       mcp_gpiostate &= ~(1 << MCP6X_SPI_CS);
+       mcp_gpiostate |= (val << MCP6X_SPI_CS);
+       mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+}
+
+static void mcp6x_bitbang_set_sck(int val)
+{
+       mcp_gpiostate &= ~(1 << MCP6X_SPI_SCK);
+       mcp_gpiostate |= (val << MCP6X_SPI_SCK);
+       mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+}
+
+static void mcp6x_bitbang_set_mosi(int val)
+{
+       mcp_gpiostate &= ~(1 << MCP6X_SPI_MOSI);
+       mcp_gpiostate |= (val << MCP6X_SPI_MOSI);
+       mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+}
+
+static int mcp6x_bitbang_get_miso(void)
+{
+       mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
+       return (mcp_gpiostate >> MCP6X_SPI_MISO) & 0x1;
+}
+
+static const struct bitbang_spi_master bitbang_spi_master_mcp6x = {
+       .type = BITBANG_SPI_MASTER_MCP,
+       .set_cs = mcp6x_bitbang_set_cs,
+       .set_sck = mcp6x_bitbang_set_sck,
+       .set_mosi = mcp6x_bitbang_set_mosi,
+       .get_miso = mcp6x_bitbang_get_miso,
+       .request_bus = mcp6x_request_spibus,
+       .release_bus = mcp6x_release_spibus,
+       .half_period = 0,
+};
+
+int mcp6x_spi_init(int want_spi)
+{
+       uint16_t status;
+       uint32_t mcp6x_spibaraddr;
+       struct pci_dev *smbusdev;
+
+       /* Look for the SMBus device (SMBus PCI class) */
+       smbusdev = pci_dev_find_vendorclass(0x10de, 0x0c05);
+       if (!smbusdev) {
+               if (want_spi) {
+                       msg_perr("ERROR: SMBus device not found. Not enabling "
+                                "SPI.\n");
+                       return 1;
+               } else {
+                       msg_pinfo("Odd. SMBus device not found.\n");
+                       return 0;
+               }
+       }
+       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. */
+       mcp6x_spibaraddr = pci_read_long(smbusdev, 0x74);
+       /* BAR size is 64k, bits 15..4 are zero, bit 3..0 declare a
+        * 32-bit non-prefetchable memory BAR.
+        */
+       mcp6x_spibaraddr &= ~0xffff;
+       msg_pdbg("MCP SPI BAR is at 0x%08x\n", mcp6x_spibaraddr);
+
+       /* Accessing a NULL pointer BAR is evil. Don't do it. */
+       if (!mcp6x_spibaraddr && want_spi) {
+               msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR "
+                        "is invalid.\n");
+               return 1;
+       } else if (!mcp6x_spibaraddr && !want_spi) {
+               msg_pdbg("MCP SPI is not used.\n");
+               return 0;
+       } else if (mcp6x_spibaraddr && !want_spi) {
+               msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently"
+                        " doesn't have SPI enabled.\n");
+               /* FIXME: Should we enable SPI anyway? */
+               return 0;
+       }
+       /* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */
+       mcp6x_spibar = physmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544);
+
+#if 0
+       /* FIXME: Run the physunmap in a shutdown function. */
+       physunmap(mcp6x_spibar, 0x544);
+#endif
+
+       status = mmio_readw(mcp6x_spibar + 0x530);
+       msg_pdbg("SPI control is 0x%04x, req=%i, gnt=%i\n",
+                status, (status >> MCP6X_SPI_REQUEST) & 0x1,
+                (status >> MCP6X_SPI_GRANT) & 0x1);
+       mcp_gpiostate = status & 0xff;
+
+       if (bitbang_spi_init(&bitbang_spi_master_mcp6x)) {
+               /* This should never happen. */
+               msg_perr("MCP6X bitbang SPI master init failed!\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+#endif
diff --git a/nic3com.c b/nic3com.c
new file mode 100644 (file)
index 0000000..f4fb6fe
--- /dev/null
+++ b/nic3com.c
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define BIOS_ROM_ADDR          0x04
+#define BIOS_ROM_DATA          0x08
+#define INT_STATUS             0x0e
+#define INTERNAL_CONFIG                0x00
+#define SELECT_REG_WINDOW      0x800
+
+#define PCI_VENDOR_ID_3COM     0x10b7
+
+static uint32_t internal_conf;
+static uint16_t id;
+
+const struct pcidev_status nics_3com[] = {
+       /* 3C90xB */
+       {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, OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" },
+
+       /* 3C980C */
+       {0x10b7, 0x9805, NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" },
+
+       {},
+};
+
+static void nic3com_chip_writeb(const struct flashctx *flash, uint8_t val,
+                               chipaddr addr);
+static uint8_t nic3com_chip_readb(const struct flashctx *flash,
+                                 const chipaddr addr);
+static const struct par_programmer par_programmer_nic3com = {
+               .chip_readb             = nic3com_chip_readb,
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = fallback_chip_readn,
+               .chip_writeb            = nic3com_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+static int nic3com_shutdown(void *data)
+{
+       /* 3COM 3C90xB cards need a special fixup. */
+       if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
+           || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
+               /* Select register window 3 and restore the receiver status. */
+               OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
+               OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG);
+       }
+
+       pci_cleanup(pacc);
+       return 0;
+}
+
+int nic3com_init(void)
+{
+       if (rget_io_perms())
+               return 1;
+
+       io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_3com);
+
+       id = pcidev_dev->device_id;
+
+       /* 3COM 3C90xB cards need a special fixup. */
+       if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
+           || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
+               /* Select register window 3 and save the receiver status. */
+               OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
+               internal_conf = INL(io_base_addr + INTERNAL_CONFIG);
+
+               /* Set receiver type to MII for full BIOS ROM access. */
+               OUTL((internal_conf & 0xf00fffff) | 0x00600000, io_base_addr);
+       }
+
+       /*
+        * The lowest 16 bytes of the I/O mapped register space of (most) 3COM
+        * cards form a 'register window' into one of multiple (usually 8)
+        * register banks. For 3C90xB/3C90xC we need register window/bank 0.
+        */
+       OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS);
+
+       if (register_shutdown(nic3com_shutdown, NULL))
+               return 1;
+
+       max_rom_decode.parallel = 128 * 1024;
+       register_par_programmer(&par_programmer_nic3com, BUS_PARALLEL);
+
+       return 0;
+}
+
+static void nic3com_chip_writeb(const struct flashctx *flash, uint8_t val,
+                               chipaddr addr)
+{
+       OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
+       OUTB(val, io_base_addr + BIOS_ROM_DATA);
+}
+
+static uint8_t nic3com_chip_readb(const struct flashctx *flash,
+                                 const chipaddr addr)
+{
+       OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
+       return INB(io_base_addr + BIOS_ROM_DATA);
+}
+
+#else
+#error PCI port I/O access is not supported on this architecture yet.
+#endif
diff --git a/nicintel.c b/nicintel.c
new file mode 100644 (file)
index 0000000..1c6d409
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011 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
+ */
+
+/* Datasheet: http://download.intel.com/design/network/datashts/82559_Fast_Ethernet_Multifunction_PCI_Cardbus_Controller_Datasheet.pdf */
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+uint8_t *nicintel_bar;
+uint8_t *nicintel_control_bar;
+
+const struct pcidev_status nics_intel[] = {
+       {PCI_VENDOR_ID_INTEL, 0x1209, NT, "Intel", "8255xER/82551IT Fast Ethernet Controller"},
+       {PCI_VENDOR_ID_INTEL, 0x1229, OK, "Intel", "82557/8/9/0/1 Ethernet Pro 100"},
+
+       {},
+};
+
+/* Arbitrary limit, taken from the datasheet I just had lying around.
+ * 128 kByte on the 82559 device. Or not. Depends on whom you ask.
+ */
+#define NICINTEL_MEMMAP_SIZE (128 * 1024)
+#define NICINTEL_MEMMAP_MASK (NICINTEL_MEMMAP_SIZE - 1)
+
+#define NICINTEL_CONTROL_MEMMAP_SIZE   0x10 
+
+#define CSR_FCR 0x0c
+
+static void nicintel_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                chipaddr addr);
+static uint8_t nicintel_chip_readb(const struct flashctx *flash,
+                                  const chipaddr addr);
+static const struct par_programmer par_programmer_nicintel = {
+               .chip_readb             = nicintel_chip_readb,
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = fallback_chip_readn,
+               .chip_writeb            = nicintel_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+static int nicintel_shutdown(void *data)
+{
+       physunmap(nicintel_control_bar, NICINTEL_CONTROL_MEMMAP_SIZE);
+       physunmap(nicintel_bar, NICINTEL_MEMMAP_SIZE);
+       pci_cleanup(pacc);
+       return 0;
+}
+
+int nicintel_init(void)
+{
+       uintptr_t addr;
+
+       /* Needed only for PCI accesses on some platforms.
+        * FIXME: Refactor that into get_mem_perms/rget_io_perms/get_pci_perms?
+        */
+       if (rget_io_perms())
+               return 1;
+
+       /* No need to check for errors, pcidev_init() will not return in case
+        * of errors.
+        * FIXME: BAR2 is not available if the device uses the CardBus function.
+        */
+       addr = pcidev_init(PCI_BASE_ADDRESS_2, nics_intel);
+
+       nicintel_bar = physmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE);
+       if (nicintel_bar == ERROR_PTR)
+               goto error_out_unmap;
+
+       /* FIXME: Using pcidev_dev _will_ cause pretty explosions in the future. */
+       addr = pcidev_readbar(pcidev_dev, PCI_BASE_ADDRESS_0);
+       /* FIXME: This is not an aligned mapping. Use 4k? */
+       nicintel_control_bar = physmap("Intel NIC control/status reg",
+                                      addr, NICINTEL_CONTROL_MEMMAP_SIZE);
+       if (nicintel_control_bar == ERROR_PTR)
+               goto error_out;
+
+       if (register_shutdown(nicintel_shutdown, NULL))
+               return 1;
+
+       /* FIXME: This register is pretty undocumented in all publicly available
+        * documentation from Intel. Let me quote the complete info we have:
+        * "Flash Control Register: The Flash Control register allows the CPU to
+        *  enable writes to an external Flash. The Flash Control Register is a
+        *  32-bit field that allows access to an external Flash device."
+        * Ah yes, we also know where it is, but we have absolutely _no_ idea
+        * what we should do with it. Write 0x0001 because we have nothing
+        * better to do with our time.
+        */
+       pci_rmmio_writew(0x0001, nicintel_control_bar + CSR_FCR);
+
+       max_rom_decode.parallel = NICINTEL_MEMMAP_SIZE;
+       register_par_programmer(&par_programmer_nicintel, BUS_PARALLEL);
+
+       return 0;
+
+error_out_unmap:
+       physunmap(nicintel_bar, NICINTEL_MEMMAP_SIZE);
+error_out:
+       pci_cleanup(pacc);
+       return 1;
+}
+
+static void nicintel_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                chipaddr addr)
+{
+       pci_mmio_writeb(val, nicintel_bar + (addr & NICINTEL_MEMMAP_MASK));
+}
+
+static uint8_t nicintel_chip_readb(const struct flashctx *flash,
+                                  const chipaddr addr)
+{
+       return pci_mmio_readb(nicintel_bar + (addr & NICINTEL_MEMMAP_MASK));
+}
diff --git a/nicintel_spi.c b/nicintel_spi.c
new file mode 100644 (file)
index 0000000..531576c
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2010 Idwer Vollering
+ *
+ * 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
+ */
+
+/*
+ * Datasheet:
+ * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual
+ * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
+ * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
+ */
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_INTEL 0x8086
+
+/* EEPROM/Flash Control & Data Register */
+#define EECD   0x10
+/* Flash Access Register */
+#define FLA    0x1c
+
+/*
+ * Register bits of EECD.
+ * Table 13-6
+ *
+ * Bit 04, 05: FWE (Flash Write Enable Control)
+ * 00b = not allowed
+ * 01b = flash writes disabled
+ * 10b = flash writes enabled
+ * 11b = not allowed
+ */
+#define FLASH_WRITES_DISABLED  0x10 /* FWE: 10000b */
+#define FLASH_WRITES_ENABLED   0x20 /* FWE: 100000b */
+
+/* Flash Access register bits
+ * Table 13-9
+ */
+#define FL_SCK 0
+#define FL_CS  1
+#define FL_SI  2
+#define FL_SO  3
+#define FL_REQ 4
+#define FL_GNT 5
+/* Currently unused */
+// #define FL_BUSY     30
+// #define FL_ER       31
+
+uint8_t *nicintel_spibar;
+
+const struct pcidev_status nics_intel_spi[] = {
+       {PCI_VENDOR_ID_INTEL, 0x105e, OK, "Intel", "82571EB Gigabit Ethernet Controller"},
+       {PCI_VENDOR_ID_INTEL, 0x1076, OK, "Intel", "82541GI Gigabit Ethernet Controller"},
+       {PCI_VENDOR_ID_INTEL, 0x107c, OK, "Intel", "82541PI Gigabit Ethernet Controller"},
+       {PCI_VENDOR_ID_INTEL, 0x10b9, OK, "Intel", "82572EI Gigabit Ethernet Controller"},
+
+       {},
+};
+
+static void nicintel_request_spibus(void)
+{
+       uint32_t tmp;
+
+       tmp = pci_mmio_readl(nicintel_spibar + FLA);
+       tmp |= 1 << FL_REQ;
+       pci_mmio_writel(tmp, nicintel_spibar + FLA);
+
+       /* Wait until we are allowed to use the SPI bus. */
+       while (!(pci_mmio_readl(nicintel_spibar + FLA) & (1 << FL_GNT))) ;
+}
+
+static void nicintel_release_spibus(void)
+{
+       uint32_t tmp;
+
+       tmp = pci_mmio_readl(nicintel_spibar + FLA);
+       tmp &= ~(1 << FL_REQ);
+       pci_mmio_writel(tmp, nicintel_spibar + FLA);
+}
+
+static void nicintel_bitbang_set_cs(int val)
+{
+       uint32_t tmp;
+
+       tmp = pci_mmio_readl(nicintel_spibar + FLA);
+       tmp &= ~(1 << FL_CS);
+       tmp |= (val << FL_CS);
+       pci_mmio_writel(tmp,  nicintel_spibar + FLA);
+}
+
+static void nicintel_bitbang_set_sck(int val)
+{
+       uint32_t tmp;
+
+       tmp = pci_mmio_readl(nicintel_spibar + FLA);
+       tmp &= ~(1 << FL_SCK);
+       tmp |= (val << FL_SCK);
+       pci_mmio_writel(tmp, nicintel_spibar + FLA);
+}
+
+static void nicintel_bitbang_set_mosi(int val)
+{
+       uint32_t tmp;
+
+       tmp = pci_mmio_readl(nicintel_spibar + FLA);
+       tmp &= ~(1 << FL_SI);
+       tmp |= (val << FL_SI);
+       pci_mmio_writel(tmp, nicintel_spibar + FLA);
+}
+
+static int nicintel_bitbang_get_miso(void)
+{
+       uint32_t tmp;
+
+       tmp = pci_mmio_readl(nicintel_spibar + FLA);
+       tmp = (tmp >> FL_SO) & 0x1;
+       return tmp;
+}
+
+static const struct bitbang_spi_master bitbang_spi_master_nicintel = {
+       .type = BITBANG_SPI_MASTER_NICINTEL,
+       .set_cs = nicintel_bitbang_set_cs,
+       .set_sck = nicintel_bitbang_set_sck,
+       .set_mosi = nicintel_bitbang_set_mosi,
+       .get_miso = nicintel_bitbang_get_miso,
+       .request_bus = nicintel_request_spibus,
+       .release_bus = nicintel_release_spibus,
+       .half_period = 1,
+};
+
+static int nicintel_spi_shutdown(void *data)
+{
+       uint32_t tmp;
+
+       /* Disable writes manually. See the comment about EECD in
+        * nicintel_spi_init() for details.
+        */
+       tmp = pci_mmio_readl(nicintel_spibar + EECD);
+       tmp &= ~FLASH_WRITES_ENABLED;
+       tmp |= FLASH_WRITES_DISABLED;
+       pci_mmio_writel(tmp, nicintel_spibar + EECD);
+
+       physunmap(nicintel_spibar, 4096);
+       pci_cleanup(pacc);
+
+       return 0;
+}
+
+int nicintel_spi_init(void)
+{
+       uint32_t tmp;
+
+       if (rget_io_perms())
+               return 1;
+
+       io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_intel_spi);
+
+       nicintel_spibar = physmap("Intel Gigabit NIC w/ SPI flash",
+                                 io_base_addr, 4096);
+       /* Automatic restore of EECD on shutdown is not possible because EECD
+        * does not only contain FLASH_WRITES_DISABLED|FLASH_WRITES_ENABLED,
+        * but other bits with side effects as well. Those other bits must be
+        * left untouched.
+        */
+       tmp = pci_mmio_readl(nicintel_spibar + EECD);
+       tmp &= ~FLASH_WRITES_DISABLED;
+       tmp |= FLASH_WRITES_ENABLED;
+       pci_mmio_writel(tmp, nicintel_spibar + EECD);
+
+       /* test if FWE is really set to allow writes */
+       tmp = pci_mmio_readl(nicintel_spibar + EECD);
+       if ( (tmp & FLASH_WRITES_DISABLED) || !(tmp & FLASH_WRITES_ENABLED) ) {
+               msg_perr("Enabling flash write access failed.\n");
+               return 1;
+       }
+
+       if (register_shutdown(nicintel_spi_shutdown, NULL))
+               return 1;
+
+       if (bitbang_spi_init(&bitbang_spi_master_nicintel))
+               return 1;
+
+       return 0;
+}
diff --git a/nicnatsemi.c b/nicnatsemi.c
new file mode 100644 (file)
index 0000000..7cdd2fe
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Andrew Morgan <ziltro@ziltro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_NATSEMI  0x100b
+
+#define BOOT_ROM_ADDR          0x50
+#define BOOT_ROM_DATA          0x54
+
+const struct pcidev_status nics_natsemi[] = {
+       {0x100b, 0x0020, NT, "National Semiconductor", "DP83815/DP83816"},
+       {0x100b, 0x0022, NT, "National Semiconductor", "DP83820"},
+       {},
+};
+
+static void nicnatsemi_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                  chipaddr addr);
+static uint8_t nicnatsemi_chip_readb(const struct flashctx *flash,
+                                    const chipaddr addr);
+static const struct par_programmer par_programmer_nicnatsemi = {
+               .chip_readb             = nicnatsemi_chip_readb,
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = fallback_chip_readn,
+               .chip_writeb            = nicnatsemi_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+static int nicnatsemi_shutdown(void *data)
+{
+       pci_cleanup(pacc);
+       return 0;
+}
+
+int nicnatsemi_init(void)
+{
+       if (rget_io_perms())
+               return 1;
+
+       io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_natsemi);
+
+       if (register_shutdown(nicnatsemi_shutdown, NULL))
+               return 1;
+
+       /* The datasheet shows address lines MA0-MA16 in one place and MA0-MA15
+        * in another. My NIC has MA16 connected to A16 on the boot ROM socket
+        * so I'm assuming it is accessible. If not then next line wants to be
+        * max_rom_decode.parallel = 65536; and the mask in the read/write
+        * functions below wants to be 0x0000FFFF.
+        */
+       max_rom_decode.parallel = 131072;
+       register_par_programmer(&par_programmer_nicnatsemi, BUS_PARALLEL);
+
+       return 0;
+}
+
+static void nicnatsemi_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                  chipaddr addr)
+{
+       OUTL((uint32_t)addr & 0x0001FFFF, io_base_addr + BOOT_ROM_ADDR);
+       /*
+        * The datasheet requires 32 bit accesses to this register, but it seems
+        * that requirement might only apply if the register is memory mapped.
+        * Bits 8-31 of this register are apparently don't care, and if this
+        * register is I/O port mapped, 8 bit accesses to the lowest byte of the
+        * register seem to work fine. Due to that, we ignore the advice in the
+        * data sheet.
+        */
+       OUTB(val, io_base_addr + BOOT_ROM_DATA);
+}
+
+static uint8_t nicnatsemi_chip_readb(const struct flashctx *flash,
+                                    const chipaddr addr)
+{
+       OUTL(((uint32_t)addr & 0x0001FFFF), io_base_addr + BOOT_ROM_ADDR);
+       /*
+        * The datasheet requires 32 bit accesses to this register, but it seems
+        * that requirement might only apply if the register is memory mapped.
+        * Bits 8-31 of this register are apparently don't care, and if this
+        * register is I/O port mapped, 8 bit accesses to the lowest byte of the
+        * register seem to work fine. Due to that, we ignore the advice in the
+        * data sheet.
+        */
+       return INB(io_base_addr + BOOT_ROM_DATA);
+}
+
+#else
+#error PCI port I/O access is not supported on this architecture yet.
+#endif
diff --git a/nicrealtek.c b/nicrealtek.c
new file mode 100644 (file)
index 0000000..afc3d0f
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Joerg Fischer <turboj@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_REALTEK  0x10ec
+#define PCI_VENDOR_ID_SMC1211  0x1113
+
+#define BIOS_ROM_ADDR          0xD4
+#define BIOS_ROM_DATA          0xD7
+
+const struct pcidev_status nics_realtek[] = {
+       {0x10ec, 0x8139, OK, "Realtek", "RTL8139/8139C/8139C+"},
+       {0x1113, 0x1211, OK, "SMC2", "1211TX"}, /* RTL8139 clone */
+       {},
+};
+
+static void nicrealtek_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                  chipaddr addr);
+static uint8_t nicrealtek_chip_readb(const struct flashctx *flash,
+                                    const chipaddr addr);
+static const struct par_programmer par_programmer_nicrealtek = {
+               .chip_readb             = nicrealtek_chip_readb,
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = fallback_chip_readn,
+               .chip_writeb            = nicrealtek_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+static int nicrealtek_shutdown(void *data)
+{
+       /* FIXME: We forgot to disable software access again. */
+       pci_cleanup(pacc);
+       return 0;
+}
+
+int nicrealtek_init(void)
+{
+       if (rget_io_perms())
+               return 1;
+
+       io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, nics_realtek);
+
+       if (register_shutdown(nicrealtek_shutdown, NULL))
+               return 1;
+
+       register_par_programmer(&par_programmer_nicrealtek, BUS_PARALLEL);
+
+       return 0;
+}
+
+static void nicrealtek_chip_writeb(const struct flashctx *flash, uint8_t val,
+                                  chipaddr addr)
+{
+       /* Output addr and data, set WE to 0, set OE to 1, set CS to 0,
+        * enable software access.
+        */
+       OUTL(((uint32_t)addr & 0x01FFFF) | 0x0A0000 | (val << 24),
+            io_base_addr + BIOS_ROM_ADDR);
+       /* Output addr and data, set WE to 1, set OE to 1, set CS to 1,
+        * enable software access.
+        */
+       OUTL(((uint32_t)addr & 0x01FFFF) | 0x1E0000 | (val << 24),
+            io_base_addr + BIOS_ROM_ADDR);
+}
+
+static uint8_t nicrealtek_chip_readb(const struct flashctx *flash,
+                                    const chipaddr addr)
+{
+       uint8_t val;
+
+       /* FIXME: Can we skip reading the old data and simply use 0? */
+       /* Read old data. */
+       val = INB(io_base_addr + BIOS_ROM_DATA);
+       /* Output new addr and old data, set WE to 1, set OE to 0, set CS to 0,
+        * enable software access.
+        */
+       OUTL(((uint32_t)addr & 0x01FFFF) | 0x060000 | (val << 24),
+            io_base_addr + BIOS_ROM_ADDR);
+
+       /* Read new data. */
+       val = INB(io_base_addr + BIOS_ROM_DATA);
+       /* Output addr and new data, set WE to 1, set OE to 1, set CS to 1,
+        * enable software access.
+        */
+       OUTL(((uint32_t)addr & 0x01FFFF) | 0x1E0000 | (val << 24),
+            io_base_addr + BIOS_ROM_ADDR);
+
+       return val;
+}
+
+#else
+#error PCI port I/O access is not supported on this architecture yet.
+#endif
diff --git a/ogp_spi.c b/ogp_spi.c
new file mode 100644 (file)
index 0000000..13091b4
--- /dev/null
+++ b/ogp_spi.c
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Mark Marshall
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_OGP 0x1227
+
+/* These are the register addresses for the OGD1 / OGA1.  If they are
+ * different for later versions of the hardware then we will need
+ * logic to select between the different hardware versions. */
+#define OGA1_XP10_BPROM_SI                          0x0040 /*  W */
+#define OGA1_XP10_BPROM_SO                          0x0040 /*  R */
+#define OGA1_XP10_BPROM_CE_BAR                      0x0044 /*  W */
+#define OGA1_XP10_BPROM_SCK                         0x0048 /*  W */
+#define OGA1_XP10_BPROM_REG_SEL                             0x004C /*  W */
+#define OGA1_XP10_CPROM_SI                          0x0050 /*  W */
+#define OGA1_XP10_CPROM_SO                          0x0050 /*  R */
+#define OGA1_XP10_CPROM_CE_BAR                      0x0054 /*  W */
+#define OGA1_XP10_CPROM_SCK                         0x0058 /*  W */
+#define OGA1_XP10_CPROM_REG_SEL                             0x005C /*  W */
+
+static uint8_t *ogp_spibar;
+
+static uint32_t ogp_reg_sel;
+static uint32_t ogp_reg_siso;
+static uint32_t ogp_reg__ce;
+static uint32_t ogp_reg_sck;
+
+const struct pcidev_status ogp_spi[] = {
+       {PCI_VENDOR_ID_OGP, 0x0000, OK, "Open Graphics Project", "Development Board OGD1"},
+       {},
+};
+
+static void ogp_request_spibus(void)
+{
+       pci_mmio_writel(1, ogp_spibar + ogp_reg_sel);
+}
+
+static void ogp_release_spibus(void)
+{
+       pci_mmio_writel(0, ogp_spibar + ogp_reg_sel);
+}
+
+static void ogp_bitbang_set_cs(int val)
+{
+       pci_mmio_writel(val, ogp_spibar + ogp_reg__ce);
+}
+
+static void ogp_bitbang_set_sck(int val)
+{
+       pci_mmio_writel(val, ogp_spibar + ogp_reg_sck);
+}
+
+static void ogp_bitbang_set_mosi(int val)
+{
+       pci_mmio_writel(val, ogp_spibar + ogp_reg_siso);
+}
+
+static int ogp_bitbang_get_miso(void)
+{
+       uint32_t tmp;
+
+       tmp = pci_mmio_readl(ogp_spibar + ogp_reg_siso);
+       return tmp & 0x1;
+}
+
+static const struct bitbang_spi_master bitbang_spi_master_ogp = {
+       .type = BITBANG_SPI_MASTER_OGP,
+       .set_cs = ogp_bitbang_set_cs,
+       .set_sck = ogp_bitbang_set_sck,
+       .set_mosi = ogp_bitbang_set_mosi,
+       .get_miso = ogp_bitbang_get_miso,
+       .request_bus = ogp_request_spibus,
+       .release_bus = ogp_release_spibus,
+       .half_period = 0,
+};
+
+static int ogp_spi_shutdown(void *data)
+{
+       physunmap(ogp_spibar, 4096);
+       pci_cleanup(pacc);
+
+       return 0;
+}
+
+int ogp_spi_init(void)
+{
+       char *type;
+
+       type = extract_programmer_param("rom");
+
+       if (!type) {
+               msg_perr("Please use flashrom -p ogp_spi:rom=... to specify "
+                        "which flashchip you want to access.\n");
+               return 1;
+       } else if (!strcasecmp(type, "bprom") || !strcasecmp(type, "bios")) {
+               ogp_reg_sel  = OGA1_XP10_BPROM_REG_SEL;
+               ogp_reg_siso = OGA1_XP10_BPROM_SI;
+               ogp_reg__ce  = OGA1_XP10_BPROM_CE_BAR;
+               ogp_reg_sck  = OGA1_XP10_BPROM_SCK;
+       } else if (!strcasecmp(type, "cprom") || !strcasecmp(type, "s3")) {
+               ogp_reg_sel  = OGA1_XP10_CPROM_REG_SEL;
+               ogp_reg_siso = OGA1_XP10_CPROM_SI;
+               ogp_reg__ce  = OGA1_XP10_CPROM_CE_BAR;
+               ogp_reg_sck  = OGA1_XP10_CPROM_SCK;
+       } else {
+               msg_perr("Invalid or missing rom= parameter.\n");
+               return 1;
+       }
+
+       if (rget_io_perms())
+               return 1;
+
+       io_base_addr = pcidev_init(PCI_BASE_ADDRESS_0, ogp_spi);
+
+       ogp_spibar = physmap("OGP registers", io_base_addr, 4096);
+
+       if (register_shutdown(ogp_spi_shutdown, NULL))
+               return 1;
+
+       if (bitbang_spi_init(&bitbang_spi_master_ogp))
+               return 1;
+
+       return 0;
+}
diff --git a/opaque.c b/opaque.c
new file mode 100644 (file)
index 0000000..6acaa63
--- /dev/null
+++ b/opaque.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011 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
+ */
+
+/*
+ * Contains the opaque programmer framework.
+ * An opaque programmer is a programmer which does not provide direct access
+ * to the flash chip and which abstracts all flash chip properties into a
+ * programmer specific interface.
+ */
+
+#include <stdint.h>
+#include "flash.h"
+#include "flashchips.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+
+int probe_opaque(struct flashctx *flash)
+{
+       return flash->pgm->opaque.probe(flash);
+}
+
+int read_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+       return flash->pgm->opaque.read(flash, buf, start, len);
+}
+
+int write_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+       return flash->pgm->opaque.write(flash, buf, start, len);
+}
+
+int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen)
+{
+       return flash->pgm->opaque.erase(flash, blockaddr, blocklen);
+}
+
+int register_opaque_programmer(const struct opaque_programmer *pgm)
+{
+       struct registered_programmer rpgm;
+
+       if (!pgm->probe || !pgm->read || !pgm->write || !pgm->erase) {
+               msg_perr("%s called with incomplete programmer definition. "
+                        "Please report a bug at flashrom@flashrom.org\n",
+                        __func__);
+               return ERROR_FLASHROM_BUG;
+       }
+       rpgm.buses_supported = BUS_PROG;
+       rpgm.opaque = *pgm;
+       return register_programmer(&rpgm);
+}
diff --git a/os.h b/os.h
new file mode 100644 (file)
index 0000000..f1b366f
--- /dev/null
+++ b/os.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011 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 OS checking.
+ */
+
+// Solaris
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+#define __FLASHROM_OS__ "SunOS"
+// OS X
+#elif defined(__MACH__) && defined(__APPLE__)
+#define __FLASHROM_OS__ "Darwin"
+// FreeBSD
+#elif defined(__FreeBSD__)
+#define __FLASHROM_OS__ "FreeBSD"
+// FreeBSD with glibc-based userspace (e.g. Debian/kFreeBSD)
+#elif defined(__FreeBSD_kernel__) && defined(__GLIBC__)
+#define __FLASHROM_OS__ "FreeBSD-glibc"
+// DragonFlyBSD
+#elif defined(__DragonFly__)
+#define __FLASHROM_OS__ "DragonFlyBSD"
+// NetBSD
+#elif defined(__NetBSD__)
+#define __FLASHROM_OS__ "NetBSD"
+// OpenBSD
+#elif defined(__OpenBSD__)
+#define __FLASHROM_OS__ "OpenBSD"
+// DJGPP
+#elif defined(__DJGPP__)
+#define __FLASHROM_OS__ "DOS"
+// MinGW (always has _WIN32 available)
+#elif defined(__MINGW32__)
+#define __FLASHROM_OS__ "MinGW"
+// Cygwin (usually without _WIN32)
+#elif defined( __CYGWIN__)
+#define __FLASHROM_OS__ "Cygwin"
+// libpayload
+#elif defined(__LIBPAYLOAD__)
+#define __FLASHROM_OS__ "libpayload"
+// Linux
+#elif defined(__linux__)
+#define __FLASHROM_OS__ "Linux"
+#endif
+__FLASHROM_OS__
diff --git a/pcidev.c b/pcidev.c
new file mode 100644 (file)
index 0000000..c1b6d6a
--- /dev/null
+++ b/pcidev.c
@@ -0,0 +1,313 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010, 2011 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 <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+uint32_t io_base_addr;
+struct pci_access *pacc;
+struct pci_dev *pcidev_dev = NULL;
+
+enum pci_bartype {
+       TYPE_MEMBAR,
+       TYPE_IOBAR,
+       TYPE_ROMBAR,
+       TYPE_UNKNOWN
+};
+
+uintptr_t pcidev_readbar(struct pci_dev *dev, int bar)
+{
+       uint64_t addr;
+       uint32_t upperaddr;
+       uint8_t headertype;
+       uint16_t supported_cycles;
+       enum pci_bartype bartype = TYPE_UNKNOWN;
+
+
+       headertype = pci_read_byte(dev, PCI_HEADER_TYPE) & 0x7f;
+       msg_pspew("PCI header type 0x%02x\n", headertype);
+
+       /* Don't use dev->base_addr[x] (as value for 'bar'), won't work on older libpci. */
+       addr = pci_read_long(dev, bar);
+
+       /* Sanity checks. */
+       switch (headertype) {
+       case PCI_HEADER_TYPE_NORMAL:
+               switch (bar) {
+               case PCI_BASE_ADDRESS_0:
+               case PCI_BASE_ADDRESS_1:
+               case PCI_BASE_ADDRESS_2:
+               case PCI_BASE_ADDRESS_3:
+               case PCI_BASE_ADDRESS_4:
+               case PCI_BASE_ADDRESS_5:
+                       if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+                               bartype = TYPE_IOBAR;
+                       else
+                               bartype = TYPE_MEMBAR;
+                       break;
+               case PCI_ROM_ADDRESS:
+                       bartype = TYPE_ROMBAR;
+                       break;
+               }
+               break;
+       case PCI_HEADER_TYPE_BRIDGE:
+               switch (bar) {
+               case PCI_BASE_ADDRESS_0:
+               case PCI_BASE_ADDRESS_1:
+                       if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+                               bartype = TYPE_IOBAR;
+                       else
+                               bartype = TYPE_MEMBAR;
+                       break;
+               case PCI_ROM_ADDRESS1:
+                       bartype = TYPE_ROMBAR;
+                       break;
+               }
+               break;
+       case PCI_HEADER_TYPE_CARDBUS:
+               break;
+       default:
+               msg_perr("Unknown PCI header type 0x%02x, BAR type cannot be determined reliably.\n",
+                        headertype);
+               break;
+       }
+
+       supported_cycles = pci_read_word(dev, PCI_COMMAND);
+
+       msg_pdbg("Requested BAR is ");
+       switch (bartype) {
+       case TYPE_MEMBAR:
+               msg_pdbg("MEM");
+               if (!(supported_cycles & PCI_COMMAND_MEMORY)) {
+                       msg_perr("MEM BAR access requested, but device has MEM space accesses disabled.\n");
+                       /* TODO: Abort here? */
+               }
+               msg_pdbg(", %sbit, %sprefetchable\n",
+                        ((addr & 0x6) == 0x0) ? "32" : (((addr & 0x6) == 0x4) ? "64" : "reserved"),
+                        (addr & 0x8) ? "" : "not ");
+               if ((addr & 0x6) == 0x4) {
+                       /* The spec says that a 64-bit register consumes
+                        * two subsequent dword locations.
+                        */
+                       upperaddr = pci_read_long(dev, bar + 4);
+                       if (upperaddr != 0x00000000) {
+                               /* Fun! A real 64-bit resource. */
+                               if (sizeof(uintptr_t) != sizeof(uint64_t)) {
+                                       msg_perr("BAR unreachable!");
+                                       /* TODO: Really abort here? If multiple PCI devices match,
+                                        * we might never tell the user about the other devices.
+                                        */
+                                       return 0;
+                               }
+                               addr |= (uint64_t)upperaddr << 32;
+                       }
+               }
+               addr &= PCI_BASE_ADDRESS_MEM_MASK;
+               break;
+       case TYPE_IOBAR:
+               msg_pdbg("I/O\n");
+#if __FLASHROM_HAVE_OUTB__
+               if (!(supported_cycles & PCI_COMMAND_IO)) {
+                       msg_perr("I/O BAR access requested, but device has I/O space accesses disabled.\n");
+                       /* TODO: Abort here? */
+               }
+#else
+               msg_perr("I/O BAR access requested, but flashrom does not support I/O BAR access on this "
+                        "platform (yet).\n");
+#endif
+               addr &= PCI_BASE_ADDRESS_IO_MASK;
+               break;
+       case TYPE_ROMBAR:
+               msg_pdbg("ROM\n");
+               /* Not sure if this check is needed. */
+               if (!(supported_cycles & PCI_COMMAND_MEMORY)) {
+                       msg_perr("MEM BAR access requested, but device has MEM space accesses disabled.\n");
+                       /* TODO: Abort here? */
+               }
+               addr &= PCI_ROM_ADDRESS_MASK;
+               break;
+       case TYPE_UNKNOWN:
+               msg_perr("BAR type unknown, please report a bug at flashrom@flashrom.org\n");
+       }
+
+       return (uintptr_t)addr;
+}
+
+uintptr_t pcidev_init(int bar, const struct pcidev_status *devs)
+{
+       struct pci_dev *dev;
+       struct pci_filter filter;
+       char *pcidev_bdf;
+       char *msg = NULL;
+       int found = 0;
+       int i;
+       uintptr_t addr = 0, curaddr = 0;
+
+       pacc = pci_alloc();     /* Get the pci_access structure */
+       pci_init(pacc);         /* Initialize the PCI library */
+       pci_scan_bus(pacc);     /* We want to get the list of devices */
+       pci_filter_init(pacc, &filter);
+
+       /* Filter by bb:dd.f (if supplied by the user). */
+       pcidev_bdf = extract_programmer_param("pci");
+       if (pcidev_bdf != NULL) {
+               if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) {
+                       msg_perr("Error: %s\n", msg);
+                       exit(1);
+               }
+       }
+       free(pcidev_bdf);
+
+       for (dev = pacc->devices; dev; dev = dev->next) {
+               if (pci_filter_match(&filter, dev)) {
+                       /* Check against list of supported devices. */
+                       for (i = 0; devs[i].device_name != NULL; i++)
+                               if ((dev->vendor_id == devs[i].vendor_id) &&
+                                   (dev->device_id == devs[i].device_id))
+                                       break;
+                       /* Not supported, try the next one. */
+                       if (devs[i].device_name == NULL)
+                               continue;
+
+                       msg_pdbg("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);
+                       if (devs[i].status == NT)
+                               msg_pinfo("===\nThis PCI device is UNTESTED. Please report the 'flashrom -p "
+                                         "xxxx' output \n"
+                                         "to flashrom@flashrom.org if it works for you. Please add the name "
+                                         "of your\n"
+                                         "PCI device to the subject. Thank you for your help!\n===\n");
+
+                       /* FIXME: We should count all matching devices, not
+                        * just those with a valid BAR.
+                        */
+                       if ((addr = pcidev_readbar(dev, bar)) != 0) {
+                               curaddr = addr;
+                               pcidev_dev = dev;
+                               found++;
+                       }
+               }
+       }
+
+       /* Only continue if exactly one supported PCI dev has been found. */
+       if (found == 0) {
+               msg_perr("Error: No supported PCI device found.\n");
+               exit(1);
+       } else if (found > 1) {
+               msg_perr("Error: Multiple supported PCI devices found. Use 'flashrom -p xxxx:pci=bb:dd.f' \n"
+                        "to explicitly select the card with the given BDF (PCI bus, device, function).\n");
+               exit(1);
+       }
+
+       return curaddr;
+}
+
+void print_supported_pcidevs(const struct pcidev_status *devs)
+{
+       int i;
+
+       msg_pinfo("PCI devices:\n");
+       for (i = 0; devs[i].vendor_name != NULL; i++) {
+               msg_pinfo("%s %s [%04x:%04x]%s\n", devs[i].vendor_name,
+                         devs[i].device_name, devs[i].vendor_id,
+                         devs[i].device_id,
+                         (devs[i].status == NT) ? " (untested)" : "");
+       }
+}
+
+enum pci_write_type {
+       pci_write_type_byte,
+       pci_write_type_word,
+       pci_write_type_long,
+};
+
+struct undo_pci_write_data {
+       struct pci_dev dev;
+       int reg;
+       enum pci_write_type type;
+       union {
+               uint8_t bytedata;
+               uint16_t worddata;
+               uint32_t longdata;
+       };
+};
+
+int undo_pci_write(void *p)
+{
+       struct undo_pci_write_data *data = p;
+       msg_pdbg("Restoring PCI config space for %02x:%02x:%01x reg 0x%02x\n",
+                data->dev.bus, data->dev.dev, data->dev.func, data->reg);
+       switch (data->type) {
+       case pci_write_type_byte:
+               pci_write_byte(&data->dev, data->reg, data->bytedata);
+               break;
+       case pci_write_type_word:
+               pci_write_word(&data->dev, data->reg, data->worddata);
+               break;
+       case pci_write_type_long:
+               pci_write_long(&data->dev, data->reg, data->longdata);
+               break;
+       }
+       /* p was allocated in register_undo_pci_write. */
+       free(p);
+       return 0;
+}
+
+#define register_undo_pci_write(a, b, c)                               \
+{                                                                      \
+       struct undo_pci_write_data *undo_pci_write_data;                \
+       undo_pci_write_data = malloc(sizeof(struct undo_pci_write_data)); \
+       if (!undo_pci_write_data) {                                     \
+               msg_gerr("Out of memory!\n");                           \
+               exit(1);                                                \
+       }                                                               \
+       undo_pci_write_data->dev = *a;                                  \
+       undo_pci_write_data->reg = b;                                   \
+       undo_pci_write_data->type = pci_write_type_##c;                 \
+       undo_pci_write_data->c##data = pci_read_##c(dev, reg);          \
+       register_shutdown(undo_pci_write, undo_pci_write_data);         \
+}
+
+#define register_undo_pci_write_byte(a, b) register_undo_pci_write(a, b, byte)
+#define register_undo_pci_write_word(a, b) register_undo_pci_write(a, b, word)
+#define register_undo_pci_write_long(a, b) register_undo_pci_write(a, b, long)
+
+int rpci_write_byte(struct pci_dev *dev, int reg, uint8_t data)
+{
+       register_undo_pci_write_byte(dev, reg);
+       return pci_write_byte(dev, reg, data);
+}
+int rpci_write_word(struct pci_dev *dev, int reg, uint16_t data)
+{
+       register_undo_pci_write_word(dev, reg);
+       return pci_write_word(dev, reg, data);
+}
+int rpci_write_long(struct pci_dev *dev, int reg, uint32_t data)
+{
+       register_undo_pci_write_long(dev, reg);
+       return pci_write_long(dev, reg, data);
+}
diff --git a/physmap.c b/physmap.c
new file mode 100644 (file)
index 0000000..eca6760
--- /dev/null
+++ b/physmap.c
@@ -0,0 +1,525 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Peter Stuge <peter@stuge.se>
+ * Copyright (C) 2009 coresystems GmbH
+ * Copyright (C) 2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2010 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "hwaccess.h"
+
+/* Do we need any file access or ioctl for physmap or MSR? */
+#if !defined(__DJGPP__) && !defined(__LIBPAYLOAD__)
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#ifdef __DJGPP__
+#include <dpmi.h>
+#include <sys/nearptr.h>
+
+#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 ERROR_PTR;
+
+       if (__djgpp_map_physical_memory(realmem_map, (1024 * 1024), 0)) {
+               free(realmem_map);
+               realmem_map = NULL;
+               return ERROR_PTR;
+       }
+
+       return realmem_map + phys_addr;
+}
+
+static 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 ERROR_PTR;
+
+       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 ERROR_PTR;
+
+       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;
+
+       /* There is no known way to unmap the first 1 MB. The DPMI server will
+        * do this for us on exit.
+        */
+       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(__LIBPAYLOAD__)
+#include <arch/virtual.h>
+
+#define MEM_DEV ""
+
+void *sys_physmap(unsigned long phys_addr, size_t len)
+{
+       return (void *)phys_to_virt(phys_addr);
+}
+
+#define sys_physmap_rw_uncached        sys_physmap
+#define sys_physmap_ro_cached  sys_physmap
+
+void physunmap(void *virt_addr, size_t len)
+{
+}
+
+int setup_cpu_msr(int cpu)
+{
+       return 0;
+}
+
+void cleanup_cpu_msr(void)
+{
+}
+#elif defined(__DARWIN__)
+
+#define MEM_DEV "DirectHW"
+
+static void *sys_physmap(unsigned long phys_addr, size_t len)
+{
+       /* The short form of ?: is a GNU extension.
+        * FIXME: map_physical returns NULL both for errors and for success
+        * if the region is mapped at virtual address zero. If in doubt, report
+        * an error until a better interface exists.
+        */
+       return map_physical(phys_addr, len) ? : ERROR_PTR;
+}
+
+/* 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);
+}
+
+#else
+#include <sys/mman.h>
+
+#if defined (__sun) && (defined(__i386) || defined(__amd64))
+#  define MEM_DEV "/dev/xsvc"
+#else
+#  define MEM_DEV "/dev/mem"
+#endif
+
+static int fd_mem = -1;
+static int fd_mem_cached = -1;
+
+/* For MMIO access. Must be uncached, doesn't make sense to restrict to ro. */
+static void *sys_physmap_rw_uncached(unsigned long phys_addr, size_t len)
+{
+       void *virt_addr;
+
+       if (-1 == fd_mem) {
+               /* Open the memory device UNCACHED. Important for MMIO. */
+               if (-1 == (fd_mem = open(MEM_DEV, O_RDWR | O_SYNC))) {
+                       perror("Critical error: open(" MEM_DEV ")");
+                       exit(2);
+               }
+       }
+
+       virt_addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED,
+                        fd_mem, (off_t)phys_addr);
+       return MAP_FAILED == virt_addr ? ERROR_PTR : virt_addr;
+}
+
+/* For reading DMI/coreboot/whatever tables. We should never write, and we
+ * do not care about caching.
+ */
+static 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))) {
+                       msg_perr("Critical error: open(" MEM_DEV "): %s",
+                                strerror(errno));
+                       exit(2);
+               }
+       }
+
+       virt_addr = mmap(NULL, len, PROT_READ, MAP_SHARED,
+                        fd_mem_cached, (off_t)phys_addr);
+       return MAP_FAILED == virt_addr ? ERROR_PTR : virt_addr;
+}
+
+void physunmap(void *virt_addr, size_t len)
+{
+       if (len == 0) {
+               msg_pspew("Not unmapping zero size at %p\n", virt_addr);
+               return;
+       }
+               
+       munmap(virt_addr, len);
+}
+#endif
+
+#define PHYSMAP_NOFAIL 0
+#define PHYSMAP_MAYFAIL        1
+#define PHYSMAP_RW     0
+#define PHYSMAP_RO     1
+
+static void *physmap_common(const char *descr, unsigned long phys_addr,
+                           size_t len, int mayfail, int readonly)
+{
+       void *virt_addr;
+
+       if (len == 0) {
+               msg_pspew("Not mapping %s, zero size at 0x%08lx.\n",
+                         descr, phys_addr);
+               return ERROR_PTR;
+       }
+
+       if ((getpagesize() - 1) & len) {
+               msg_perr("Mapping %s at 0x%08lx, unaligned size 0x%lx.\n",
+                        descr, phys_addr, (unsigned long)len);
+       }
+
+       if ((getpagesize() - 1) & phys_addr) {
+               msg_perr("Mapping %s, 0x%lx bytes at unaligned 0x%08lx.\n",
+                        descr, (unsigned long)len, phys_addr);
+       }
+
+       if (readonly)
+               virt_addr = sys_physmap_ro_cached(phys_addr, len);
+       else
+               virt_addr = sys_physmap_rw_uncached(phys_addr, len);
+
+       if (ERROR_PTR == virt_addr) {
+               if (NULL == descr)
+                       descr = "memory";
+               msg_perr("Error accessing %s, 0x%lx bytes at 0x%08lx\n", descr,
+                        (unsigned long)len, phys_addr);
+               perror(MEM_DEV " mmap failed");
+#ifdef __linux__
+               if (EINVAL == errno) {
+                       msg_perr("In Linux this error can be caused by the CONFIG_NONPROMISC_DEVMEM (<2.6.27),\n");
+                       msg_perr("CONFIG_STRICT_DEVMEM (>=2.6.27) and CONFIG_X86_PAT kernel options.\n");
+                       msg_perr("Please check if either is enabled in your kernel before reporting a failure.\n");
+                       msg_perr("You can override CONFIG_X86_PAT at boot with the nopat kernel parameter but\n");
+                       msg_perr("disabling the other option unfortunately requires a kernel recompile. Sorry!\n");
+               }
+#elif defined (__OpenBSD__)
+               msg_perr("Please set securelevel=-1 in /etc/rc.securelevel "
+                        "and reboot, or reboot into\n"
+                        "single user mode.\n");
+#endif
+               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);
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifdef __linux__
+/*
+ * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr,
+ * which are ring0 privileged instructions so only the kernel can do the
+ * read/write. This function, therefore, requires that the msr kernel module
+ * be loaded to access these instructions from user space using device
+ * /dev/cpu/0/msr.
+ */
+
+static int fd_msr = -1;
+
+msr_t rdmsr(int addr)
+{
+       uint32_t buf[2];
+       msr_t msr = { 0xffffffff, 0xffffffff };
+
+       if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
+               perror("Could not lseek() to MSR");
+               close(fd_msr);
+               exit(1);
+       }
+
+       if (read(fd_msr, buf, 8) == 8) {
+               msr.lo = buf[0];
+               msr.hi = buf[1];
+               return msr;
+       }
+
+       if (errno != EIO) {
+               // A severe error.
+               perror("Could not read() MSR");
+               close(fd_msr);
+               exit(1);
+       }
+
+       return msr;
+}
+
+int wrmsr(int addr, msr_t msr)
+{
+       uint32_t buf[2];
+       buf[0] = msr.lo;
+       buf[1] = msr.hi;
+
+       if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
+               perror("Could not lseek() to MSR");
+               close(fd_msr);
+               exit(1);
+       }
+
+       if (write(fd_msr, buf, 8) != 8 && errno != EIO) {
+               perror("Could not write() MSR");
+               close(fd_msr);
+               exit(1);
+       }
+
+       /* Some MSRs must not be written. */
+       if (errno == EIO)
+               return -1;
+
+       return 0;
+}
+
+int setup_cpu_msr(int cpu)
+{
+       char msrfilename[64];
+       memset(msrfilename, 0, sizeof(msrfilename));
+       snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu/%d/msr", cpu);
+
+       if (fd_msr != -1) {
+               msg_pinfo("MSR was already initialized\n");
+               return -1;
+       }
+
+       fd_msr = open(msrfilename, O_RDWR);
+
+       if (fd_msr < 0) {
+               perror("Error while opening /dev/cpu/0/msr");
+               msg_pinfo("Did you run 'modprobe msr'?\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void cleanup_cpu_msr(void)
+{
+       if (fd_msr == -1) {
+               msg_pinfo("No MSR initialized.\n");
+               return;
+       }
+
+       close(fd_msr);
+
+       /* Clear MSR file descriptor. */
+       fd_msr = -1;
+}
+#else
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <sys/ioctl.h>
+
+typedef struct {
+       int msr;
+       uint64_t data;
+} cpu_msr_args_t;
+#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t)
+#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t)
+
+static int fd_msr = -1;
+
+msr_t rdmsr(int addr)
+{
+       cpu_msr_args_t args;
+
+       msr_t msr = { 0xffffffff, 0xffffffff };
+
+       args.msr = addr;
+
+       if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) {
+               perror("CPU_RDMSR");
+               close(fd_msr);
+               exit(1);
+       }
+
+       msr.lo = args.data & 0xffffffff;
+       msr.hi = args.data >> 32;
+
+       return msr;
+}
+
+int wrmsr(int addr, msr_t msr)
+{
+       cpu_msr_args_t args;
+
+       args.msr = addr;
+       args.data = (((uint64_t)msr.hi) << 32) | msr.lo;
+
+       if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) {
+               perror("CPU_WRMSR");
+               close(fd_msr);
+               exit(1);
+       }
+
+       return 0;
+}
+
+int setup_cpu_msr(int cpu)
+{
+       char msrfilename[64];
+       memset(msrfilename, 0, sizeof(msrfilename));
+       snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu%d", cpu);
+
+       if (fd_msr != -1) {
+               msg_pinfo("MSR was already initialized\n");
+               return -1;
+       }
+
+       fd_msr = open(msrfilename, O_RDWR);
+
+       if (fd_msr < 0) {
+               perror("Error while opening /dev/cpu0");
+               msg_pinfo("Did you install ports/sysutils/devcpu?\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void cleanup_cpu_msr(void)
+{
+       if (fd_msr == -1) {
+               msg_pinfo("No MSR initialized.\n");
+               return;
+       }
+
+       close(fd_msr);
+
+       /* Clear MSR file descriptor. */
+       fd_msr = -1;
+}
+
+#else
+
+#ifdef __DARWIN__
+int setup_cpu_msr(int cpu)
+{
+       // Always succeed for now
+       return 0;
+}
+
+void cleanup_cpu_msr(void)
+{
+       // Nothing, yet.
+}
+#elif defined(__LIBPAYLOAD__)
+msr_t libpayload_rdmsr(int addr)
+{
+       msr_t msr;
+       unsigned long long val = _rdmsr(addr);
+       msr.lo = val & 0xffffffff;
+       msr.hi = val >> 32;
+       return msr;
+}
+
+int libpayload_wrmsr(int addr, msr_t msr)
+{
+       _wrmsr(addr, msr.lo | ((unsigned long long)msr.hi << 32));
+       return 0;
+}
+#else
+msr_t rdmsr(int addr)
+{
+       msr_t ret = { 0xffffffff, 0xffffffff };
+
+       return ret;
+}
+
+int wrmsr(int addr, msr_t msr)
+{
+       return -1;
+}
+
+int setup_cpu_msr(int cpu)
+{
+       msg_pinfo("No MSR support for your OS yet.\n");
+       return -1;
+}
+
+void cleanup_cpu_msr(void)
+{
+       // Nothing, yet.
+}
+#endif
+#endif
+#endif
+#else
+/* Does MSR exist on non-x86 architectures? */
+#endif
diff --git a/pm49fl00x.c b/pm49fl00x.c
new file mode 100644 (file)
index 0000000..42db2aa
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2004 Tyan Corporation
+ * Copyright (C) 2007 Nikolay Petukhov <nikolay.petukhov@gmail.com>
+ * Copyright (C) 2007 Reinder E.N. de Haan <lb_reha@mveas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+
+static void write_lockbits_49fl00x(const struct flashctx *flash,
+                                  unsigned int size, unsigned char bits,
+                                  unsigned int block_size)
+{
+       unsigned int i, left = size;
+       chipaddr bios = flash->virtual_registers;
+
+       for (i = 0; left >= block_size; i++, left -= block_size) {
+               /* pm49fl002 */
+               if (block_size == 16384 && i % 2)
+                       continue;
+
+               chip_writeb(flash, bits, bios + (i * block_size) + 2);
+       }
+}
+
+int unlock_49fl00x(struct flashctx *flash)
+{
+       write_lockbits_49fl00x(flash, flash->total_size * 1024, 0,
+                              flash->page_size);
+       return 0;
+}
+
+int lock_49fl00x(struct flashctx *flash)
+{
+       write_lockbits_49fl00x(flash, flash->total_size * 1024, 1,
+                              flash->page_size);
+       return 0;
+}
diff --git a/pony_spi.c b/pony_spi.c
new file mode 100644 (file)
index 0000000..6ce467e
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2012 Virgil-Adrian Teaca
+ *
+ * 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
+ */
+
+/* Driver for the SI-Prog like hardware by Lancos.com.
+ * See http://www.lancos.com/siprogsch.html for schematics and instructions.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "flash.h"
+#include "programmer.h"
+
+/* We have:
+
+ MOSI -----> DTR
+ MISO -----> CTS
+ SCK  --+--> RTS
+        +--> DSR
+ CS#  -----> TXD
+
+*/
+
+enum pony_type {
+       TYPE_SI_PROG,
+       TYPE_SERBANG,
+};
+
+/* The hardware programmer used. */
+static enum pony_type pony_type = TYPE_SI_PROG;
+
+static void pony_bitbang_set_cs(int val)
+{
+       if (pony_type == TYPE_SI_PROG)
+       {
+               /* CS# is negated by the SI-Prog programmer. */
+               val ^=  1;
+       }
+       sp_set_pin(PIN_TXD, val);
+}
+
+static void pony_bitbang_set_sck(int val)
+{
+       sp_set_pin(PIN_RTS, val);
+}
+
+static void pony_bitbang_set_mosi(int val)
+{
+       sp_set_pin(PIN_DTR, val);
+}
+
+static int pony_bitbang_get_miso(void)
+{
+       int tmp;
+
+       tmp = sp_get_pin(PIN_CTS);
+
+       if (pony_type == TYPE_SERBANG)
+       {
+               /* MISO is negated by the SERBANG programmer. */
+               tmp ^= 1;
+       }
+       return tmp;
+}
+
+static const struct bitbang_spi_master bitbang_spi_master_pony = {
+       .type = BITBANG_SPI_MASTER_PONY,
+       .set_cs = pony_bitbang_set_cs,
+       .set_sck = pony_bitbang_set_sck,
+       .set_mosi = pony_bitbang_set_mosi,
+       .get_miso = pony_bitbang_get_miso,
+       .half_period = 0,
+};
+
+int pony_spi_init(void)
+{
+       char *arg = NULL;
+       int i, data_in, data_out, have_device = 0;
+       int have_prog = 1;
+
+       /* The parameter is on format "dev=/dev/device,type=serbang" */
+       arg = extract_programmer_param("dev");
+
+       if (arg && strlen(arg)) {
+               sp_fd = sp_openserport( arg, 9600 );
+               if (sp_fd < 0) {
+                       free(arg);
+                       return 1;
+               }
+               have_device++;
+       }
+       free(arg);
+
+       if (!have_device) {
+               msg_perr("Error: No valid device specified.\n"
+                        "Use flashrom -p pony_spi:dev=/dev/device\n");
+
+               return 1;
+       }
+       /* Register the shutdown callback. */
+       if (register_shutdown(serialport_shutdown, NULL)) {
+               return 1;
+       }
+       arg = extract_programmer_param("type");
+
+       if (arg) {
+               if (!strcasecmp( arg, "serbang")) {
+                       pony_type = TYPE_SERBANG;
+               } else if (!strcasecmp( arg, "si_prog") ) {
+                       pony_type = TYPE_SI_PROG;
+               } else {
+                       msg_perr("Error: Invalid programmer type specified.\n");
+                       free(arg);
+                       return 1;
+               }
+       }
+       free(arg);
+
+       msg_pdbg("Using the %s programmer.\n", ((pony_type == TYPE_SI_PROG ) ? "SI-Prog" : "SERBANG"));
+       /*
+        * Detect if there is a SI-Prog compatible programmer connected.
+        */
+       pony_bitbang_set_cs(1);
+       pony_bitbang_set_mosi(1);
+
+       /* We toggle SCK while we keep MOSI and CS# on. */
+       for (i = 1; i <= 10; ++i) {
+               data_out = i & 1;
+               sp_set_pin(PIN_RTS, data_out);
+               programmer_delay( 1000 );
+               data_in = sp_get_pin(PIN_DSR);
+
+               if (data_out != data_in) {
+                       have_prog = 0;
+                       break;
+               }
+       }
+
+       if (!have_prog) {
+               msg_perr( "No SI-Prog compatible hardware detected.\n" );
+               return 1;
+       }
+
+       if (bitbang_spi_init(&bitbang_spi_master_pony)) {
+               return 1;
+       }
+       return 0;
+}
diff --git a/print.c b/print.c
new file mode 100644 (file)
index 0000000..7f64c05
--- /dev/null
+++ b/print.c
@@ -0,0 +1,1063 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+
+/*
+ * Return a string corresponding to the bustype parameter.
+ * Memory is obtained with malloc() and must be freed with free() by the caller.
+ */
+char *flashbuses_to_text(enum chipbustype bustype)
+{
+       char *ret = calloc(1, 1);
+       /*
+        * FIXME: Once all chipsets and flash chips have been updated, NONSPI
+        * will cease to exist and should be eliminated here as well.
+        */
+       if (bustype == BUS_NONSPI) {
+               ret = strcat_realloc(ret, "Non-SPI, ");
+       } else {
+               if (bustype & BUS_PARALLEL)
+                       ret = strcat_realloc(ret, "Parallel, ");
+               if (bustype & BUS_LPC)
+                       ret = strcat_realloc(ret, "LPC, ");
+               if (bustype & BUS_FWH)
+                       ret = strcat_realloc(ret, "FWH, ");
+               if (bustype & BUS_SPI)
+                       ret = strcat_realloc(ret, "SPI, ");
+               if (bustype & BUS_PROG)
+                       ret = strcat_realloc(ret, "Programmer-specific, ");
+               if (bustype == BUS_NONE)
+                       ret = strcat_realloc(ret, "None, ");
+       }
+       /* Kill last comma. */
+       ret[strlen(ret) - 2] = '\0';
+       ret = realloc(ret, strlen(ret) + 1);
+       return ret;
+}
+
+static void print_supported_chips(void)
+{
+       const char *delim = "/";
+       const int mintoklen = 5;
+       const int border = 2;
+       int i, chipcount = 0;
+       int maxvendorlen = strlen("Vendor") + 1;
+       int maxchiplen = strlen("Device") + 1;
+       int maxtypelen = strlen("Type") + 1;
+       const struct flashchip *f;
+       char *s;
+       char *tmpven, *tmpdev;
+       int tmpvenlen, tmpdevlen, curvenlen, curdevlen;
+
+       /* calculate maximum column widths and by iterating over all chips */
+       for (f = flashchips; f->name != NULL; f++) {
+               /* Ignore generic entries. */
+               if (!strncmp(f->vendor, "Unknown", 7) ||
+                   !strncmp(f->vendor, "Programmer", 10) ||
+                   !strncmp(f->name, "unknown", 7))
+                       continue;
+               chipcount++;
+
+               /* Find maximum vendor length (respecting line splitting). */
+               tmpven = (char *)f->vendor;
+               do {
+                       /* and take minimum token lengths into account */
+                       tmpvenlen = 0;
+                       do {
+                               tmpvenlen += strcspn(tmpven, delim);
+                               /* skip to the address after the first token */
+                               tmpven += tmpvenlen;
+                               if (tmpven[0] == '\0')
+                                       break;
+                               tmpven++;
+                       } while (tmpvenlen < mintoklen);
+                       maxvendorlen = max(maxvendorlen, tmpvenlen);
+                       if (tmpven[0] == '\0')
+                               break;
+               } while (1);
+
+               /* same for device name */
+               tmpdev = (char *)f->name;
+               do {
+                       tmpdevlen = 0;
+                       do {
+                               tmpdevlen += strcspn(tmpdev, delim);
+                               tmpdev += tmpdevlen;
+                               if (tmpdev[0] == '\0')
+                                       break;
+                               tmpdev++;
+                       } while (tmpdevlen < mintoklen);
+                       maxchiplen = max(maxchiplen, tmpdevlen);
+                       if (tmpdev[0] == '\0')
+                               break;
+               } while (1);
+
+               s = flashbuses_to_text(f->bustype);
+               maxtypelen = max(maxtypelen, strlen(s));
+               free(s);
+       }
+       maxvendorlen += border;
+       maxchiplen += border;
+       maxtypelen += border;
+
+       msg_ginfo("Supported flash chips (total: %d):\n\n", chipcount);
+       msg_ginfo("Vendor");
+       for (i = strlen("Vendor"); i < maxvendorlen; i++)
+               msg_ginfo(" ");
+       msg_ginfo("Device");
+       for (i = strlen("Device"); i < maxchiplen; i++)
+               msg_ginfo(" ");
+
+       msg_ginfo("Test");
+       for (i = 0; i < border; i++)
+               msg_ginfo(" ");
+       msg_ginfo("Known");
+       for (i = 0; i < border; i++)
+               msg_ginfo(" ");
+       msg_ginfo(" Size");
+       for (i = 0; i < border; i++)
+               msg_ginfo(" ");
+
+       msg_ginfo("Type");
+       for (i = strlen("Type"); i < maxtypelen; i++)
+               msg_ginfo(" ");
+       msg_gdbg("Voltage");
+       msg_ginfo("\n");
+
+       for (i = 0; i < maxvendorlen + maxchiplen; i++)
+               msg_ginfo(" ");
+       msg_ginfo("OK  ");
+       for (i = 0; i < border; i++)
+               msg_ginfo(" ");
+       msg_ginfo("Broken");
+       for (i = 0; i < border; i++)
+               msg_ginfo(" ");
+       msg_ginfo("[kB]");
+       for (i = 0; i < border + maxtypelen; i++)
+               msg_ginfo(" ");
+       msg_gdbg("range [V]");
+       msg_ginfo("\n\n");
+       msg_ginfo("(P = PROBE, R = READ, E = ERASE, W = WRITE)\n\n");
+
+       for (f = flashchips; f->name != NULL; f++) {
+               /* Don't print generic entries. */
+               if (!strncmp(f->vendor, "Unknown", 7) ||
+                   !strncmp(f->vendor, "Programmer", 10) ||
+                   !strncmp(f->name, "unknown", 7))
+                       continue;
+
+               /* support for multiline vendor names:
+                * - make a copy of the original vendor name
+                * - use strok to put the first token in tmpven
+                * - keep track of the length of all tokens on the current line
+                *   for ' '-padding in curvenlen
+                * - check if additional tokens should be printed on the current
+                *   line
+                * - after all other values are printed print the surplus tokens
+                *   on fresh lines
+                */
+               tmpven = malloc(strlen(f->vendor) + 1);
+               if (tmpven == NULL) {
+                       msg_gerr("Out of memory!\n");
+                       exit(1);
+               }
+               strcpy(tmpven, f->vendor);
+
+               tmpven = strtok(tmpven, delim);
+               msg_ginfo("%s", tmpven);
+               curvenlen = strlen(tmpven);
+               while ((tmpven = strtok(NULL, delim)) != NULL) {
+                       msg_ginfo("%s", delim);
+                       curvenlen++;
+                       tmpvenlen = strlen(tmpven);
+                       if (tmpvenlen >= mintoklen)
+                               break; /* big enough to be on its own line */
+                       msg_ginfo("%s", tmpven);
+                       curvenlen += tmpvenlen;
+               }
+
+               for (i = curvenlen; i < maxvendorlen; i++)
+                       msg_ginfo(" ");
+
+               /* support for multiline device names as above */
+               tmpdev = malloc(strlen(f->name) + 1);
+               if (tmpdev == NULL) {
+                       msg_gerr("Out of memory!\n");
+                       exit(1);
+               }
+               strcpy(tmpdev, f->name);
+
+               tmpdev = strtok(tmpdev, delim);
+               msg_ginfo("%s", tmpdev);
+               curdevlen = strlen(tmpdev);
+               while ((tmpdev = strtok(NULL, delim)) != NULL) {
+                       msg_ginfo("%s", delim);
+                       curdevlen++;
+                       tmpdevlen = strlen(tmpdev);
+                       if (tmpdevlen >= mintoklen)
+                               break; /* big enough to be on its own line */
+                       msg_ginfo("%s", tmpdev);
+                       curdevlen += tmpdevlen;
+               }
+
+               for (i = curdevlen; i < maxchiplen; i++)
+                       msg_ginfo(" ");
+
+               if ((f->tested & TEST_OK_PROBE))
+                       msg_ginfo("P");
+               else
+                       msg_ginfo(" ");
+               if ((f->tested & TEST_OK_READ))
+                       msg_ginfo("R");
+               else
+                       msg_ginfo(" ");
+               if ((f->tested & TEST_OK_ERASE))
+                       msg_ginfo("E");
+               else
+                       msg_ginfo(" ");
+               if ((f->tested & TEST_OK_WRITE))
+                       msg_ginfo("W");
+               else
+                       msg_ginfo(" ");
+               for (i = 0; i < border; i++)
+                       msg_ginfo(" ");
+
+               if ((f->tested & TEST_BAD_PROBE))
+                       msg_ginfo("P");
+               else
+                       msg_ginfo(" ");
+               if ((f->tested & TEST_BAD_READ))
+                       msg_ginfo("R");
+               else
+                       msg_ginfo(" ");
+               if ((f->tested & TEST_BAD_ERASE))
+                       msg_ginfo("E");
+               else
+                       msg_ginfo(" ");
+               if ((f->tested & TEST_BAD_WRITE))
+                       msg_ginfo("W");
+               else
+                       msg_ginfo(" ");
+               for (i = 0; i < border + 1; i++)
+                       msg_ginfo(" ");
+
+               msg_ginfo("%5d", f->total_size);
+               for (i = 0; i < border; i++)
+                       msg_ginfo(" ");
+
+               s = flashbuses_to_text(f->bustype);
+               msg_ginfo("%s", s);
+               for (i = strlen(s); i < maxtypelen; i++)
+                       msg_ginfo(" ");
+               free(s);
+
+               if (f->voltage.min == 0 && f->voltage.max == 0)
+                       msg_gdbg("no info");
+               else
+                       msg_gdbg("%0.02f;%0.02f",
+                                f->voltage.min/(double)1000,
+                                f->voltage.max/(double)1000);
+
+               /* print surplus vendor and device name tokens */
+               while (tmpven != NULL || tmpdev != NULL) {
+                       msg_ginfo("\n");
+                       if (tmpven != NULL){
+                               msg_ginfo("%s", tmpven);
+                               curvenlen = strlen(tmpven);
+                               while ((tmpven = strtok(NULL, delim)) != NULL) {
+                                       msg_ginfo("%s", delim);
+                                       curvenlen++;
+                                       tmpvenlen = strlen(tmpven);
+                                       /* big enough to be on its own line */
+                                       if (tmpvenlen >= mintoklen)
+                                               break;
+                                       msg_ginfo("%s", tmpven);
+                                       curvenlen += tmpvenlen;
+                               }
+                       } else
+                               curvenlen = 0;
+
+                       for (i = curvenlen; i < maxvendorlen; i++)
+                               msg_ginfo(" ");
+
+                       if (tmpdev != NULL){
+                               msg_ginfo("%s", tmpdev);
+                               curdevlen = strlen(tmpdev);
+                               while ((tmpdev = strtok(NULL, delim)) != NULL) {
+                                       msg_ginfo("%s", delim);
+                                       curdevlen++;
+                                       tmpdevlen = strlen(tmpdev);
+                                       /* big enough to be on its own line */
+                                       if (tmpdevlen >= mintoklen)
+                                               break;
+                                       msg_ginfo("%s", tmpdev);
+                                       curdevlen += tmpdevlen;
+                               }
+                       }
+               }
+               msg_ginfo("\n");
+       }
+}
+
+#if CONFIG_INTERNAL == 1
+static void print_supported_chipsets(void)
+{
+       int i, chipsetcount = 0;
+       const struct penable *c = chipset_enables;
+       int maxvendorlen = strlen("Vendor") + 1;
+       int maxchipsetlen = strlen("Chipset") + 1;
+
+       for (c = chipset_enables; c->vendor_name != NULL; c++) {
+               chipsetcount++;
+               maxvendorlen = max(maxvendorlen, strlen(c->vendor_name));
+               maxchipsetlen = max(maxchipsetlen, strlen(c->device_name));
+       }
+       maxvendorlen++;
+       maxchipsetlen++;
+
+       msg_ginfo("Supported chipsets (total: %d):\n\n", chipsetcount);
+
+       msg_ginfo("Vendor");
+       for (i = strlen("Vendor"); i < maxvendorlen; i++)
+               msg_ginfo(" ");
+
+       msg_ginfo("Chipset");
+       for (i = strlen("Chipset"); i < maxchipsetlen; i++)
+               msg_ginfo(" ");
+
+       msg_ginfo("PCI IDs   State\n\n");
+
+       for (c = chipset_enables; c->vendor_name != NULL; c++) {
+               msg_ginfo("%s", c->vendor_name);
+               for (i = 0; i < maxvendorlen - strlen(c->vendor_name); i++)
+                       msg_ginfo(" ");
+               msg_ginfo("%s", c->device_name);
+               for (i = 0; i < maxchipsetlen - strlen(c->device_name); i++)
+                       msg_ginfo(" ");
+               msg_ginfo("%04x:%04x%s\n", c->vendor_id, c->device_id,
+                      (c->status == NT) ? " (untested)" : "");
+       }
+}
+
+static void print_supported_boards_helper(const struct board_info *boards,
+                                  const char *devicetype)
+{
+       int i;
+       unsigned int boardcount_good = 0, boardcount_bad = 0, boardcount_nt = 0;
+       const struct board_match *e = board_matches;
+       const struct board_info *b = boards;
+       int maxvendorlen = strlen("Vendor") + 1;
+       int maxboardlen = strlen("Board") + 1;
+
+       for (b = boards; b->vendor != NULL; b++) {
+               maxvendorlen = max(maxvendorlen, strlen(b->vendor));
+               maxboardlen = max(maxboardlen, strlen(b->name));
+               if (b->working == OK)
+                       boardcount_good++;
+               else if (b->working == NT)
+                       boardcount_nt++;
+               else
+                       boardcount_bad++;
+       }
+       maxvendorlen++;
+       maxboardlen++;
+
+       msg_ginfo("%d known %s (good: %d, untested: %d, bad: %d):\n\n",
+                 boardcount_good + boardcount_nt + boardcount_bad,
+                 devicetype, boardcount_good, boardcount_nt, boardcount_bad);
+
+       msg_ginfo("Vendor");
+       for (i = strlen("Vendor"); i < maxvendorlen; i++)
+               msg_ginfo(" ");
+
+       msg_ginfo("Board");
+       for (i = strlen("Board"); i < maxboardlen; i++)
+               msg_ginfo(" ");
+
+       msg_ginfo("Status  Required value for\n");
+       for (i = 0; i < maxvendorlen + maxboardlen + strlen("Status  "); i++)
+               msg_ginfo(" ");
+       msg_ginfo("-p internal:mainboard=\n");
+
+       for (b = boards; b->vendor != NULL; b++) {
+               msg_ginfo("%s", b->vendor);
+               for (i = 0; i < maxvendorlen - strlen(b->vendor); i++)
+                       msg_ginfo(" ");
+               msg_ginfo("%s", b->name);
+               for (i = 0; i < maxboardlen - strlen(b->name); i++)
+                       msg_ginfo(" ");
+                       if (b->working == OK)
+                               msg_ginfo("OK      ");
+                       else if (b->working == NT)
+                               msg_ginfo("NT      ");
+                       else
+                               msg_ginfo("BAD     ");
+
+               for (e = board_matches; e->vendor_name != NULL; e++) {
+                       if (strcmp(e->vendor_name, b->vendor)
+                           || strcmp(e->board_name, b->name))
+                               continue;
+                       if (e->lb_vendor == NULL)
+                               msg_ginfo("(autodetected)");
+                       else
+                               msg_ginfo("%s:%s", e->lb_vendor,
+                                                  e->lb_part);
+               }
+               msg_ginfo("\n");
+       }
+}
+#endif
+
+void print_supported(void)
+{
+       print_supported_chips();
+
+       msg_ginfo("\nSupported programmers:\n");
+       list_programmers_linebreak(0, 80, 0);
+#if CONFIG_INTERNAL == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n\n",
+              programmer_table[PROGRAMMER_INTERNAL].name);
+       print_supported_chipsets();
+       msg_ginfo("\n");
+       print_supported_boards_helper(boards_known, "boards");
+       msg_ginfo("\n");
+       print_supported_boards_helper(laptops_known, "laptops");
+#endif
+#if CONFIG_DUMMY == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_DUMMY].name);
+       /* FIXME */
+       msg_ginfo("Dummy device, does nothing and logs all accesses\n");
+#endif
+#if CONFIG_NIC3COM == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_NIC3COM].name);
+       print_supported_pcidevs(nics_3com);
+#endif
+#if CONFIG_NICREALTEK == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_NICREALTEK].name);
+       print_supported_pcidevs(nics_realtek);
+#endif
+#if CONFIG_NICNATSEMI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_NICNATSEMI].name);
+       print_supported_pcidevs(nics_natsemi);
+#endif
+#if CONFIG_GFXNVIDIA == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_GFXNVIDIA].name);
+       print_supported_pcidevs(gfx_nvidia);
+#endif
+#if CONFIG_DRKAISER == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_DRKAISER].name);
+       print_supported_pcidevs(drkaiser_pcidev);
+#endif
+#if CONFIG_SATASII == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_SATASII].name);
+       print_supported_pcidevs(satas_sii);
+#endif
+#if CONFIG_ATAHPT == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_ATAHPT].name);
+       print_supported_pcidevs(ata_hpt);
+#endif
+#if CONFIG_FT2232_SPI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_FT2232_SPI].name);
+       print_supported_usbdevs(devs_ft2232spi);
+#endif
+#if CONFIG_SERPROG == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_SERPROG].name);
+       /* FIXME */
+       msg_ginfo("All programmer devices speaking the serprog protocol\n");
+#endif
+#if CONFIG_BUSPIRATE_SPI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_BUSPIRATE_SPI].name);
+       /* FIXME */
+       msg_ginfo("Dangerous Prototypes Bus Pirate\n");
+#endif
+#if CONFIG_DEDIPROG == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_DEDIPROG].name);
+       /* FIXME */
+       msg_ginfo("Dediprog SF100\n");
+#endif
+#if CONFIG_RAYER_SPI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_RAYER_SPI].name);
+       /* FIXME */
+       msg_ginfo("RayeR parallel port programmer\n");
+#endif
+#if CONFIG_PONY_SPI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_PONY_SPI].name);
+       /* FIXME */
+       msg_ginfo("SI-Prog and SERBANG serial port programmer\n");
+#endif
+#if CONFIG_NICINTEL == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_NICINTEL].name);
+       print_supported_pcidevs(nics_intel);
+#endif
+#if CONFIG_NICINTEL_SPI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_NICINTEL_SPI].name);
+       print_supported_pcidevs(nics_intel_spi);
+#endif
+#if CONFIG_OGP_SPI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_OGP_SPI].name);
+       print_supported_pcidevs(ogp_spi);
+#endif
+#if CONFIG_SATAMV == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_SATAMV].name);
+       print_supported_pcidevs(satas_mv);
+#endif
+#if CONFIG_LINUX_SPI == 1
+       msg_ginfo("\nSupported devices for the %s programmer:\n",
+              programmer_table[PROGRAMMER_LINUX_SPI].name);
+       msg_ginfo("Device files /dev/spidev*.*\n");
+#endif
+}
+
+#if CONFIG_INTERNAL == 1
+
+#ifdef CONFIG_PRINT_WIKI
+#define B(vendor, name, status, url, note) { vendor, name, status, url, note }
+#else
+#define B(vendor, name, status, url, note) { vendor, name, status }
+#endif
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info boards_known[] = {
+#if defined(__i386__) || defined(__x86_64__)
+       B("A-Trend",    "ATC-6220",             OK, "http://www.motherboard.cz/mb/atrend/atc6220.htm", NULL),
+       B("abit",       "A-S78H",               OK, NULL, NULL),
+       B("abit",       "AN-M2",                OK, NULL, NULL),
+       B("abit",       "AV8",                  OK, NULL, NULL),
+       B("abit",       "AX8",                  OK, NULL, NULL),
+       B("abit",       "BM6",                  OK, NULL, NULL),
+       B("abit",       "Fatal1ty F-I90HD",     OK, NULL, NULL),
+       B("abit",       "IC7",                  OK, NULL, NULL),
+       B("abit",       "IP35",                 OK, NULL, NULL),
+       B("abit",       "IP35 Pro",             OK, NULL, NULL),
+       B("abit",       "IS-10",                BAD, NULL, "Reported by deejkuba@aol.com to flashrom@coreboot.org, no public archive. Missing board enable and/or M50FW040 unlocking. May work now."),
+       B("abit",       "KN8 Ultra",            OK, NULL, NULL),
+       B("abit",       "NF-M2 nView",          OK, NULL, NULL),
+       B("abit",       "NF-M2S",               OK, NULL, NULL),
+       B("abit",       "NF7-S",                OK, NULL, NULL),
+       B("abit",       "VA6",                  OK, NULL, NULL),
+       B("abit",       "VT6X4",                OK, NULL, NULL),
+       B("Acorp",      "6A815EPD",             OK, "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp", NULL),
+       B("Advantech",  "PCM-5820",             OK, "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm", NULL),
+       B("agami",      "Aruma",                OK, "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series", NULL),
+       B("Albatron",   "PM266A Pro",           OK, "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56", NULL), /* FIXME */
+       B("AOpen",      "i945GMx-VFX",          OK, NULL, "This is (also?) an OEM board from FSC (used in e.g. ESPRIMO Q5010 with designation D2544-B1)."),
+       B("AOpen",      "vKM400Am-S",           OK, "http://usa.aopen.com/products_detail.aspx?Auno=824", NULL),
+       B("Artec Group","DBE61",                OK, "http://wiki.thincan.org/DBE61", NULL),
+       B("Artec Group","DBE62",                OK, "http://wiki.thincan.org/DBE62", NULL),
+       B("ASI",        "MB-5BLMP",             OK, "http://www.hojerteknik.com/winnet.htm", "Used in the IGEL WinNET III thin client."),
+       B("ASRock",     "775i65G",              OK, "http://www.asrock.com/mb/overview.asp?Model=775i65G", NULL),
+       B("ASRock",     "880G Pro3",            OK, "http://www.asrock.com/mb/overview.asp?Model=880G%20Pro3", NULL),
+       B("ASRock",     "890GX Extreme3",       OK, "http://www.asrock.com/mb/overview.asp?Model=890GX%20Extreme3", NULL),
+       B("ASRock",     "939A785GMH/128M",      OK, "http://www.asrock.com/mb/overview.asp?Model=939A785GMH/128M", NULL),
+       B("ASRock",     "A330GC",               OK, "http://www.asrock.com/mb/overview.asp?Model=A330GC", NULL),
+       B("ASRock",     "A770CrossFire",        OK, "http://www.asrock.com/mb/overview.asp?Model=A770CrossFire", NULL),
+       B("ASRock",     "A780FullHD",           OK, "http://www.asrock.com/mb/overview.asp?Model=A780FullHD", "While flashrom is working correctly, there might be problems with the firmware images themselves. Please see http://www.flashrom.org/pipermail/flashrom/2012-July/009600.html for details."),
+       B("ASRock",     "ALiveNF6G-DVI",        OK, "http://www.asrock.com/mb/overview.asp?Model=ALiveNF6G-DVI", NULL),
+       B("ASRock",     "AM2NF6G-VSTA",         OK, "http://www.asrock.com/mb/overview.asp?Model=AM2NF6G-VSTA", NULL),
+       B("ASRock",     "ConRoeXFire-eSATA2",   OK, "http://www.asrock.com/mb/overview.asp?model=conroexfire-esata2", NULL),
+       B("ASRock",     "H61M-ITX",             BAD, "http://www.asrock.com/mb/overview.asp?Model=H61M-ITX", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASRock",     "H67M",                 BAD, "http://www.asrock.com/mb/overview.asp?Model=H67M", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASRock",     "K7S41",                OK, "http://www.asrock.com/mb/overview.asp?Model=K7S41", NULL),
+       B("ASRock",     "K7S41GX",              OK, "http://www.asrock.com/mb/overview.asp?Model=K7S41GX", NULL),
+       B("ASRock",     "K7VT4A+",              BAD, "http://www.asrock.com/mb/overview.asp?Model=K7VT4A%2b", "No chip found, probably due to flash translation. http://www.flashrom.org/pipermail/flashrom/2009-August/000393.html"),
+       B("ASRock",     "K8S8X",                OK, "http://www.asrock.com/mb/overview.asp?Model=K8S8X", NULL),
+       B("ASRock",     "M3A790GXH/128M",       OK, "http://www.asrock.com/mb/overview.asp?Model=M3A790GXH/128M", NULL),
+       B("ASRock",     "N61P-S",               OK, "http://www.asrock.com/mb/overview.asp?Model=N61P-S", NULL),
+       B("ASRock",     "P4i65GV",              OK, "http://www.asrock.com/mb/overview.asp?Model=P4i65GV", NULL),
+       B("ASUS",       "A7N8X Deluxe",         OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7N8X_Deluxe/", NULL),
+       B("ASUS",       "A7N8X-E Deluxe",       OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7N8XE_Deluxe/", NULL),
+       B("ASUS",       "A7N8X-VM/400",         OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7N8XVM400/", NULL),
+       B("ASUS",       "A7V133",               OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/socka/kt133a/a7v133/", NULL),
+       B("ASUS",       "A7V333",               OK, "ftp://ftp.asus.com.tw/pub/asus/mb/socka/kt333/a7v333/", NULL),
+       B("ASUS",       "A7V400-MX",            OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7V400MX/", NULL),
+       B("ASUS",       "A7V600-X",             OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7V600X/", NULL),
+       B("ASUS",       "A7V8X",                OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7V8X/", NULL),
+       B("ASUS",       "A7V8X-MX",             OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7V8XMX/", NULL),
+       B("ASUS",       "A7V8X-MX SE",          OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7V8XMX_SE/", NULL),
+       B("ASUS",       "A7V8X-X",              OK, "http://www.asus.com/Motherboards/AMD_Socket_A/A7V8XX/", NULL),
+       B("ASUS",       "A8M2N-LA (NodusM3-GL8E)", OK, "http://h10010.www1.hp.com/ewfrf/wc/document?docname=c00757531&cc=us&dlc=en&lc=en", "This is an OEM board from HP, the HP name is NodusM3-GL8E."),
+       B("ASUS",       "A8N-E",                OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8NE/", NULL),
+       B("ASUS",       "A8N-LA (Nagami-GL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?lc=en&cc=us&docname=c00647121&dlc=en", "This is an OEM board from HP, the HP name is Nagami-GL8E."),
+       B("ASUS",       "A8N-SLI",              OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8NSLI/", NULL),
+       B("ASUS",       "A8N-SLI Deluxe",       NT, NULL, "Untested board enable."),
+       B("ASUS",       "A8N-SLI Premium",      OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8NSLI_Premium/", NULL),
+       B("ASUS",       "A8N-VM",               OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8NVM/", NULL),
+       B("ASUS",       "A8N-VM CSM",           OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8NVM_CSM/", NULL),
+       B("ASUS",       "A8NE-FM/S",            OK, "http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM", NULL),
+       B("ASUS",       "A8V Deluxe",           OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8V_Deluxe/", NULL),
+       B("ASUS",       "A8V-E Deluxe",         OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8VE_Deluxe/", NULL),
+       B("ASUS",       "A8V-E SE",             OK, "http://www.asus.com/Motherboards/AMD_Socket_939/A8VE_SE/", "See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html"),
+       B("ASUS",       "Crosshair II Formula", OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/Crosshair_II_Formula/", NULL),
+       B("ASUS",       "Crosshair IV Extreme", OK, "http://www.asus.com/Motherboards/AMD_AM3/Crosshair_IV_Extreme/", NULL),
+       B("ASUS",       "E35M1-I DELUXE",       OK, "http://www.asus.com/Motherboards/AMD_CPU_on_Board/E35M1I_DELUXE/", NULL),
+       B("ASUS",       "K8N",                  OK, "http://www.asus.com/Motherboards/AMD_Socket_754/K8N/", NULL),
+       B("ASUS",       "K8V",                  OK, "http://www.asus.com/Motherboards/AMD_Socket_754/K8V/", NULL),
+       B("ASUS",       "K8V SE Deluxe",        OK, "http://www.asus.com/Motherboards/AMD_Socket_754/K8V_SE_Deluxe/", NULL),
+       B("ASUS",       "K8V-X",                OK, "http://www.asus.com/Motherboards/AMD_Socket_754/K8VX/", NULL),
+       B("ASUS",       "K8V-X SE",             OK, "http://www.asus.com/Motherboards/AMD_Socket_754/K8VX_SE/", NULL),
+       B("ASUS",       "KFSN4-DRE/SAS",        OK, "http://www.asus.com/Server_Workstation/Server_Motherboards/KFSN4DRESAS/", NULL),
+       B("ASUS",       "M2A-MX",               OK, "http://www.asus.com/Motherboards/AMD_AM2/M2AMX/", NULL),
+       B("ASUS",       "M2A-VM (HDMI)",        OK, "http://www.asus.com/Motherboards/AMD_AM2/M2AVM/", NULL),
+       B("ASUS",       "M2N32-SLI Deluxe",     OK, "http://www.asus.com/Motherboards/AMD_AM2/M2N32SLI_DeluxeWireless_Edition/", NULL),
+       B("ASUS",       "M2N68-VM",             OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M2N68VM/", NULL),
+       B("ASUS",       "M2N-E",                OK, "http://www.asus.com/Motherboards/AMD_AM2/M2NE/", "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"),
+       B("ASUS",       "M2N-E SLI",            OK, "http://www.asus.com/Motherboards/AMD_AM2/M2NE_SLI/", NULL),
+       B("ASUS",       "M2N-SLI Deluxe",       OK, "http://www.asus.com/Motherboards/AMD_AM2/M2NSLI_Deluxe/", NULL),
+       B("ASUS",       "M2NBP-VM CSM",         OK, "http://www.asus.com/Motherboards/AMD_AM2/M2NBPVM_CSM/", NULL),
+       B("ASUS",       "M2NPV-VM",             OK, "http://www.asus.com/Motherboards/AMD_AM2/M2NPVVM/", NULL),
+       B("ASUS",       "M2V",                  OK, "http://www.asus.com/Motherboards/AMD_AM2/M2V/", NULL),
+       B("ASUS",       "M2V-MX",               OK, "http://www.asus.com/Motherboards/AMD_AM2/M2VMX/", NULL),
+       B("ASUS",       "M3A",                  OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M3A/", NULL),
+       B("ASUS",       "M3A76-CM",             OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M3A76CM/", NULL),
+       B("ASUS",       "M3A78-EM",             OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M3A78EM/", NULL),
+       B("ASUS",       "M3N78 PRO",            OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M3N78_PRO/", NULL),
+       B("ASUS",       "M3N78-VM",             OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M3N78VM/", NULL),
+       B("ASUS",       "M4A78-EM",             OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M4A78EM/", NULL),
+       B("ASUS",       "M4A785T-M",            OK, "http://www.asus.com/Motherboards/AMD_AM3/M4A785TM/", NULL),
+       B("ASUS",       "M4A785TD-M EVO",       OK, "http://www.asus.com/Motherboards/AMD_AM3/M4A785TDM_EVO/", NULL),
+       B("ASUS",       "M4A785TD-V EVO",       OK, "http://www.asus.com/Motherboards/AMD_AM3/M4A785TDV_EVO/", NULL),
+       B("ASUS",       "M4A78LT-M LE",         OK, "http://www.asus.com/Motherboards/AMD_AM3/M4A78LTM_LE/", NULL),
+       B("ASUS",       "M4A79T Deluxe",        OK, "http://www.asus.com/Motherboards/AMD_AM3/M4A79T_Deluxe/", NULL),
+       B("ASUS",       "M4A87TD/USB3",         OK, "http://www.asus.com/Motherboards/AMD_AM3/M4A87TDUSB3/", NULL),
+       B("ASUS",       "M4A89GTD PRO",         OK, "http://www.asus.com/Motherboards/AMD_AM3/M4A89GTD_PRO/", NULL),
+       B("ASUS",       "M4N68T V2",            OK, "http://www.asus.com/Motherboards/AMD_AM3/M4N68T_V2/", NULL),
+       B("ASUS",       "M4N78 PRO",            OK, "http://www.asus.com/Motherboards/AMD_AM2Plus/M4N78_PRO/", NULL),
+       B("ASUS",       "M5A78L-M LX",          OK, "http://www.asus.com/Motherboards/AMD_AM3Plus/M5A78LM_LX/", "The MAC address of the onboard LAN NIC is stored in flash, hence overwritten by flashrom; see http://www.flashrom.org/pipermail/flashrom/2012-May/009200.html"),
+       B("ASUS",       "M5A99X EVO",           OK, "http://www.asus.com/Motherboards/AMD_AM3Plus/M5A99X_EVO/", NULL),
+       B("ASUS",       "Maximus IV Extreme",   BAD, "http://www.asus.com/Motherboards/Intel_Socket_1155/Maximus_IV_Extreme/", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "MEW-AM",               BAD, "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock370/810/mew-am/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+       B("ASUS",       "MEW-VM",               BAD, "http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+       B("ASUS",       "OPLX-M",               NT, NULL, "Untested board enable."),
+       B("ASUS",       "P2B",                  OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b/", NULL),
+       B("ASUS",       "P2B-D",                OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/", NULL),
+       B("ASUS",       "P2B-DS",               OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-ds/", NULL),
+       B("ASUS",       "P2B-F",                OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/", NULL),
+       B("ASUS",       "P2B-N",                OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-n/", NULL),
+       B("ASUS",       "P2E-M",                OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440ex/p2e-m/", NULL),
+       B("ASUS",       "P2L97-S",              OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440lx/p2l97-s/", NULL),
+       B("ASUS",       "P3B-F",                BAD, "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p3b-f/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+       B("ASUS",       "P4B266",               OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock478/p4b266/", NULL),
+       B("ASUS",       "P4B266-LM",            OK, "http://esupport.sony.com/US/perl/swu-list.pl?mdl=PCVRX650", NULL),
+       B("ASUS",       "P4B533-E",             OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock478/p4b533-e/", NULL),
+       B("ASUS",       "P4C800-E Deluxe",      OK, "http://www.asus.com/Motherboards/Intel_Socket_478/P4C800E_Deluxe/", NULL),
+       B("ASUS",       "P4GV-LA (Guppy)",      OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00363478", NULL),
+       B("ASUS",       "P4P800",               OK, "http://www.asus.com/Motherboards/Intel_Socket_478/P4P800/", NULL),
+       B("ASUS",       "P4P800-E Deluxe",      OK, "http://www.asus.com/Motherboards/Intel_Socket_478/P4P800E_Deluxe/", NULL),
+       B("ASUS",       "P4P800-VM",            OK, "http://www.asus.com/Motherboards/Intel_Socket_478/P4P800VM/", NULL),
+       B("ASUS",       "P4S533-X",             OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock478/p4s533-x/", NULL),
+       B("ASUS",       "P4S800-MX",            OK, "http://www.asus.com/Motherboards/Intel_Socket_478/P4S800MX/", NULL),
+       B("ASUS",       "P4SC-E",               OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock478/p4sc-e/", "Part of ASUS Terminator P4 533 barebone system"),
+       B("ASUS",       "P4SD-LA",              OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00022505", NULL),
+       B("ASUS",       "P5A",                  OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock7/ali/p5a/", NULL),
+       B("ASUS",       "P5B",                  OK, "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B/", NULL),
+       B("ASUS",       "P5B-Deluxe",           OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5B_Deluxe/", NULL),
+       B("ASUS",       "P5BV-M",               BAD, "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-VM/", "Reported by Bernhard M. Wiedemann <bernhard@uml12d.zq1.de> to flashrom@coreboot.org, no public archive. Missing board enable and/or SST49LF008A unlocking. May work now."),
+       B("ASUS",       "P5BV-R",               OK, "http://www.asus.com/Server_Workstation/Servers/RS120E5PA2/", "Used in RS120-E5/PA2 servers."),
+       B("ASUS",       "P5GC-MX/1333",         OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5GCMX1333/", NULL),
+       B("ASUS",       "P5GD1 Pro",            OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5GD1_PRO/", NULL),
+       B("ASUS",       "P5GD1-VM/S",           OK, NULL, "This is an OEM board from FSC. Although flashrom supports it and can probably not distinguish it from the P5GD1-VM, please note that the P5GD1-VM BIOS does not support the FSC variants completely."),
+       B("ASUS",       "P5GD1(-VM)",           NT, NULL, "Untested board enable."),
+       B("ASUS",       "P5GD2 Premium",        OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5GD2_Premium/", NULL),
+       B("ASUS",       "P5GD2-X",              OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5GD2X/", NULL),
+       B("ASUS",       "P5GDC Deluxe",         OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5GDC_Deluxe/", NULL),
+       B("ASUS",       "P5GDC-V Deluxe",       OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5GDCV_Deluxe/", NULL),
+       B("ASUS",       "P5GD2/C variants",     NT, NULL, "Untested board enable."),
+       B("ASUS",       "P5K-V",                OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5KV/", NULL),
+       B("ASUS",       "P5K-VM",               OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5KVM/", NULL),
+       B("ASUS",       "P5KC",                 OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5KC/", NULL),
+       B("ASUS",       "P5KPL-CM",             OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5KPLCM/", NULL),
+       B("ASUS",       "P5L-MX",               OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LMX/", NULL),
+       B("ASUS",       "P5L-VM 1394",          OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LVM_1394/", NULL),
+       B("ASUS",       "P5LD2",                NT, NULL, "Untested board enable."),
+       B("ASUS",       "P5LP-LE (Lithium-UL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00379616&tmp_task=prodinfoCategory&cc=us&dlc=en&lc=en&product=1159887", "This is an OEM board from HP."),
+       B("ASUS",       "P5LP-LE (Epson OEM)",  OK, NULL, "This is an OEM board from Epson (e.g. Endeavor MT7700)."),
+       B("ASUS",       "P5LP-LE",              NT, NULL, "This designation is used for OEM boards from HP, Epson and maybe others. The HP names vary and not all of them have been tested yet. Please report any success or failure, thanks."),
+       B("ASUS",       "P5N-E SLI",            NT, "http://www.asus.com/Motherboards/Intel_Socket_775/P5NE_SLI/", "Untested board enable"),
+       B("ASUS",       "P5N-D",                OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5ND/", NULL),
+       B("ASUS",       "P5N-E SLI",            NT, "http://www.asus.com/Motherboards/Intel_Socket_775/P5NE_SLI/", "Untested board enable."),
+       B("ASUS",       "P5N32-E SLI",          OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5N32E_SLI/", NULL),
+       B("ASUS",       "P5N7A-VM",             OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5N7AVM/", NULL),
+       B("ASUS",       "P5ND2-SLI Deluxe",     OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5ND2SLI_Deluxe/", NULL),
+       B("ASUS",       "P5PE-VM",              OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5PEVM/", NULL),
+       B("ASUS",       "P5QPL-AM",             OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5QPLAM/", NULL),
+       B("ASUS",       "P5VD1-X",              OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5VD1X/", NULL),
+       B("ASUS",       "P5VD2-MX",             OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5VD2MX/", "The MAC address of the onboard LAN NIC is stored in flash, hence overwritten by flashrom; see http://www.flashrom.org/pipermail/flashrom/2012-March/009014.html"),
+       B("ASUS",       "P6T SE",               OK, "http://www.asus.com/Motherboards/Intel_Socket_1366/P6T_SE/", NULL),
+       B("ASUS",       "P6T Deluxe",           OK, "http://www.asus.com/Motherboards/Intel_Socket_1366/P6T_Deluxe/", NULL),
+       B("ASUS",       "P6T Deluxe V2",        OK, "http://www.asus.com/Motherboards/Intel_Socket_1366/P6T_Deluxe_V2/", NULL),
+       B("ASUS",       "P7H57D-V EVO",         OK, "http://www.asus.com/Motherboards/Intel_Socket_1156/P7H57DV_EVO/", NULL),
+       B("ASUS",       "P7H55-M LX",           BAD, NULL, "flashrom works correctly, but GbE LAN is nonworking (probably due to a missing/bogus MAC address; see http://www.flashrom.org/pipermail/flashrom/2011-July/007432.html and http://ubuntuforums.org/showthread.php?t=1534389 for a possible workaround)"),
+       B("ASUS",       "P8B-E/4L",             BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8B WS",               BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8H61 PRO",            BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8H61-M LE/USB3",      BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8H67-M PRO",          BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8P67 (rev. 3.1)",     BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8P67 LE",             BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8P67 PRO (rev. 3.0)", OK, "http://www.asus.com/Motherboards/Intel_Socket_1155/P8P67_PRO/", NULL),
+       B("ASUS",       "P8Z68-V",              OK, "http://www.asus.com/Motherboards/Intel_Socket_1155/P8Z68V/", "Warning: MAC address of LOM is stored at 0x1000 - 0x1005 of the image."),
+       B("ASUS",       "P8Z68-V PRO",          BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ASUS",       "P8Z68-V PRO/GEN3",     OK, "http://www.asus.com/Motherboards/Intel_Socket_1155/P8Z68V_PROGEN3/", "Warning: MAC address of LOM is stored at 0x1000 - 0x1005 of the image."),
+       B("ASUS",       "SABERTOOTH 990FX",     OK, "http://www.asus.com/Motherboards/AMD_AM3Plus/SABERTOOTH_990FX/", NULL),
+       B("ASUS",       "TUSL2-C",              NT, "http://support.asus.com/download.aspx?SLanguage=en&p=1&s=4&m=TUSL2-C&os=&hashedid=n/a", "Untested board enable."),
+       B("ASUS",       "Z8NA-D6C",             OK, "http://www.asus.com/Server_Workstation/Server_Motherboards/Z8NAD6C/", NULL),
+       B("ASUS",       "Z8PE-D12",             OK, "http://www.asus.com/Server_Workstation/Server_Motherboards/Z8PED12/", NULL),
+       B("Bachmann",   "OT200",                OK, "http://www.bachmann.info/produkte/bedien-und-beobachtungsgeraete/operator-terminals/", NULL),
+       B("BCOM",       "WinNET100",            OK, "http://www.coreboot.org/BCOM_WINNET100", "Used in the IGEL-316 thin client."),
+       B("Bifferos",   "Bifferboard",          OK, "http://bifferos.co.uk/", NULL),
+       B("Biostar",    "H61MU3",               BAD, NULL, "Probing works (Eon EN25Q32(A/B), 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("Biostar",    "M6TBA",                BAD, "ftp://ftp.biostar-usa.com/manuals/M6TBA/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+       B("Biostar",    "M7NCD Pro",            OK, "http://www.biostar.com.tw/app/en/mb/content.php?S_ID=260", NULL),
+       B("Biostar",    "M7VIQ",                BAD, NULL, "Missing board enable (W83697HF/F/HG/G), see http://www.flashrom.org/pipermail/flashrom/2012-February/008863.html"),
+       B("Biostar",    "N61PB-M2S",            OK, NULL, NULL),
+       B("Biostar",    "N68S3+",               OK, NULL, NULL),
+       B("Biostar",    "P4M80-M4",             OK, "http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4", NULL),
+       B("Biostar",    "TA780G M2+",           OK, "http://www.biostar.com.tw/app/en/t-series/content.php?S_ID=344", NULL),
+       B("Boser",      "HS-6637",              BAD, "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf", "Reported by Mark Robinson <mark@zl2tod.net> to flashrom@coreboot.org, no public archive. Missing board enable and/or F29C51002T unlocking. May work now."),
+       B("Congatec",   "conga-X852",           OK, "http://www.congatec.com/single_news+M57715f6263d.html?&L=1", NULL),
+       B("Dell",       "Inspiron 580",         BAD, "http://support.dell.com/support/edocs/systems/insp580/en/index.htm", "Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+       B("Dell",       "OptiPlex GX1",         OK, "http://support.dell.com/support/edocs/systems/ban_gx1/en/index.htm", NULL),
+       B("Dell",       "PowerEdge 1850",       OK, "http://support.dell.com/support/edocs/systems/pe1850/en/index.htm", NULL),
+       B("Dell",       "Vostro 460",           BAD, "http://support.dell.com/support/edocs/systems/vos460/en/index.htm", "Mainboard model is 0Y2MRG. Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+       B("DFI",        "855GME-MGF",           BAD, "http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433", "Probably needs a board enable. http://www.coreboot.org/pipermail/coreboot/2009-May/048549.html"),
+       B("DFI",        "Blood-Iron P35 T2RL",  OK, "http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1", NULL),
+       B("Elitegroup", "GeForce6100SM-M ",     OK, "http://www.ecs.com.tw/ECSWebSite/Product/Product_Detail.aspx?DetailID=685&MenuID=24", NULL),
+       B("Elitegroup", "GF7100PVT-M3 (V1.0)",  OK, "http://www.ecs.com.tw/ECSWebSite/Product/Product_Detail.aspx?DetailID=853&CategoryID=1&DetailName=Specification&MenuID=24&LanID=0", NULL),
+       B("Elitegroup", "GF8200A",              OK, "http://www.ecs.com.tw/ECSWebSite/Product/Product_Detail.aspx?DetailID=873&CategoryID=1&MenuID=20&LanID=0", NULL),
+       B("Elitegroup", "K7S5A",                OK, "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=279&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0", NULL),
+       B("Elitegroup", "K7S6A",                OK, "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=77&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0", NULL),
+       B("Elitegroup", "K7SEM (V1.0A)",        OK, "http://www.ecs.com.tw/ECSWebSite/Product/Product_Detail.aspx?DetailID=229&CategoryID=1&DetailName=Specification&MenuID=24&LanID=0", NULL),
+       B("Elitegroup", "K7VTA3",               OK, "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=264&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0", NULL),
+       B("Elitegroup", "P4M800PRO-M (V1.0A, V2.0)", OK, "http://www.ecs.com.tw/ECSWebSite_2007/Products/ProductsDetail.aspx?CategoryID=1&DetailID=574&DetailName=Feature&MenuID=52&LanID=0", NULL),
+       B("Elitegroup", "P4VXMS (V1.0A)",       OK, NULL, NULL),
+       B("Elitegroup", "P6IWP-Fe",             OK, "http://www.ecs.com.tw/ECSWebSite_2007/Products/ProductsDetail.aspx?CategoryID=1&TypeID=3&DetailID=95&DetailName=Feature&MenuID=1&LanID=0", NULL),
+       B("Elitegroup", "P6VAP-A+",             OK, "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=117&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0", NULL),
+       B("Elitegroup", "RS485M-M",             OK, "http://www.ecs.com.tw/ECSWebSite_2007/Products/ProductsDetail.aspx?CategoryID=1&DetailID=654&DetailName=Feature&MenuID=1&LanID=0", NULL),
+       B("Emerson",    "ATCA-7360",            OK, "http://www.emerson.com/sites/Network_Power/en-US/Products/Product_Detail/Product1/Pages/EmbCompATCA-7360.aspx", NULL),
+       B("EPoX",       "EP-3PTA",              BAD, NULL, "Missing board enable (W83627HF/F/HG/G), see http://www.flashrom.org/pipermail/flashrom/2012-April/009043.html"),
+       B("EPoX",       "EP-8K5A2",             OK, "http://www.epox.com/product.asp?ID=EP-8K5A2", NULL),
+       B("EPoX",       "EP-8NPA7I",            OK, "http://www.epox.com/product.asp?ID=EP-8NPA7I", NULL),
+       B("EPoX",       "EP-8RDA3+",            OK, "http://www.epox.com/product.asp?ID=EP-8RDA3plus", NULL),
+       B("EPoX",       "EP-9NPA7I",            OK, "http://www.epox.com/product.asp?ID=EP-9NPA7I", NULL),
+       B("EPoX",       "EP-BX3",               OK, "http://www.epox.com/product.asp?ID=EP-BX3", NULL),
+       B("EVGA",       "132-CK-NF78",          OK, "http://www.evga.com/articles/385.asp", NULL),
+       B("EVGA",       "270-WS-W555-A2 (Classified SR-2)", OK, "http://www.evga.com/products/moreInfo.asp?pn=270-WS-W555-A2", NULL),
+       B("FIC",        "VA-502",               BAD, "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. Seems the PCI subsystem IDs are identical with the Tekram P6Pro-A5. May work now."),
+       B("Foxconn",    "6150K8MD-8EKRSH",      OK, "http://www.foxconnchannel.com/product/motherboards/detail_overview.aspx?id=en-us0000157", NULL),
+       B("Foxconn",    "A6VMX",                OK, "http://www.foxconnchannel.com/product/motherboards/detail_overview.aspx?id=en-us0000346", NULL),
+       B("Foxconn",    "P4M800P7MA-RS2",       OK, "http://www.foxconnchannel.com/Product/Motherboards/detail_overview.aspx?id=en-us0000138", NULL),
+       B("Freetech",   "P6F91i",               OK, "http://web.archive.org/web/20010417035034/http://www.freetech.com/prod/P6F91i.html", NULL),
+       B("Fujitsu-Siemens", "ESPRIMO P5915",   OK, "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/professionalpc/ESPRIMO/P/EsprimoP5915-6.htm", "Mainboard model is D2312-A2."),
+       B("Fujitsu-Siemens", "CELSIUS W410",    BAD, "ftp://ftp.ts.fujitsu.com/pub/mainboard-oem-sales/Products/Mainboards/Industrial&ExtendedLifetime/D3061&D3062/", "Mainboard model is D3062-A1. Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+       B("GIGABYTE",   "GA-2761GXDK",          OK, "http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/", NULL),
+       B("GIGABYTE",   "GA-6BXC",              OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1445", NULL),
+       B("GIGABYTE",   "GA-6BXDU",             OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1429", NULL),
+       B("GIGABYTE",   "GA-6IEM",              OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1379", NULL),
+       B("GIGABYTE",   "GA-6VXE7+",            OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2410", NULL),
+       B("GIGABYTE",   "GA-6ZMA",              OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1541", NULL),
+       B("GIGABYTE",   "GA-MA785GMT-UD2H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3156", NULL),
+       B("GIGABYTE",   "GA-770TA-UD3",         OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3272", NULL),
+       B("GIGABYTE",   "GA-7DXR",              OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1302", NULL),
+       B("GIGABYTE",   "GA-7VT600",            OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1666", NULL),
+       B("GIGABYTE",   "GA-7ZM",               OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1366", "Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option."),
+       B("GIGABYTE",   "GA-880GMA-USB3 (rev. 3.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3817", NULL),
+       B("GIGABYTE",   "GA-8I945GZME-RH",      OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2304", NULL),
+       B("GIGABYTE",   "GA-8IP775",            OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1830", NULL),
+       B("GIGABYTE",   "GA-8IRML",             OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1343", NULL),
+       B("GIGABYTE",   "GA-8PE667 Ultra 2",    OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1607", NULL),
+       B("GIGABYTE",   "GA-8SIMLH",            OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1399", NULL),
+       B("GIGABYTE",   "GA-945PL-S3P (rev. 6.6)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2541", NULL),
+       B("GIGABYTE",   "GA-965GM-S2 (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2617", NULL),
+       B("GIGABYTE",   "GA-965P-DS4",          OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2288", NULL),
+       B("GIGABYTE",   "GA-EP31-DS3L (rev. 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2964", NULL),
+       B("GIGABYTE",   "GA-EP35-DS3L",         OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2778", NULL),
+       B("GIGABYTE",   "GA-H61M-D2-B3",        OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3773", NULL),
+       B("GIGABYTE",   "GA-H61M-D2H-USB3",     OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4004", NULL),
+       B("GIGABYTE",   "GA-EX58-UD4P",         OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2986", NULL),
+       B("GIGABYTE",   "GA-K8N-SLI",           OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1928", NULL),
+       B("GIGABYTE",   "GA-K8N51GMF",          OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1950", NULL),
+       B("GIGABYTE",   "GA-K8N51GMF-9",        OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1939", NULL),
+       B("GIGABYTE",   "GA-K8NS Pro-939",      NT, "http://www.gigabyte.com/products/product-page.aspx?pid=1875", "Untested board enable."),
+       B("GIGABYTE",   "GA-M57SLI-S4",         OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2287", NULL),
+       B("GIGABYTE",   "GA-M61P-S3",           OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2434", NULL),
+       B("GIGABYTE",   "GA-M720-US3",          OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3006", NULL),
+       B("GIGABYTE",   "GA-MA69VM-S2",         OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2500", NULL),
+       B("GIGABYTE",   "GA-MA74GM-S2H (rev. 3.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3152", NULL),
+       B("GIGABYTE",   "GA-MA770-UD3 (rev. 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3302", NULL),
+       B("GIGABYTE",   "GA-MA770T-UD3P",       OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3096", NULL),
+       B("GIGABYTE",   "GA-MA780G-UD3H",       OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3004", NULL),
+       B("GIGABYTE",   "GA-MA78G-DS3H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2800", NULL),
+       B("GIGABYTE",   "GA-MA78GM-S2H",        OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2758", NULL), /* TODO: Rev. 1.BAD, 1.OK, or 2.x? */
+       B("GIGABYTE",   "GA-MA78GPM-DS2H",      OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2859", NULL),
+       B("GIGABYTE",   "GA-MA790FX-DQ6",       OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2690", NULL),
+       B("GIGABYTE",   "GA-MA790GP-DS4H",      OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2887", NULL),
+       B("GIGABYTE",   "GA-MA790XT-UD4P (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3010", NULL),
+       B("GIGABYTE",   "GA-P55A-UD4 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3436", NULL),
+       B("GIGABYTE",   "GA-P67A-UD3P",         OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3649", NULL),
+       B("GIGABYTE",   "GA-X58A-UD7 (rev. 2.0)", OK, NULL, NULL),
+       B("GIGABYTE",   "GA-X58A-UDR3 (rev. 2.0)", OK, NULL, NULL),
+       B("GIGABYTE",   "GA-Z68MX-UD2H-B (rev. 1.3)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3854", NULL),
+       B("GIGABYTE",   "GA-Z68XP-UD3 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3892", NULL),
+       B("HP",         "8100 Elite CMT PC (304Bh)", BAD, NULL, "SPI lock down, PR, read-only descriptor, locked ME region."),
+       B("HP",         "e-Vectra P2706T",      OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodSeriesId=77515&prodTypeId=12454", NULL),
+       B("HP",         "ProLiant DL145 G3",    OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351", NULL),
+       B("HP",         "ProLiant DL165 G6",    OK, "http://h10010.www1.hp.com/wwpc/us/en/sm/WF05a/15351-15351-3328412-241644-3328421-3955644.html", NULL),
+       B("HP",         "ProLiant N40L",        OK, NULL, NULL),
+       B("HP",         "Puffer2-UL8E",         OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00300023", NULL),
+       B("HP",         "dc7800",               BAD, "http://h10010.www1.hp.com/wwpc/us/en/sm/WF06a/12454-12454-64287-321860-3328898-3459241.html?dnr=1", "ICH9DO with SPI lock down, BIOS lock, PR, read-only descriptor, locked ME region."),
+       B("HP",         "Vectra VL400",         OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060658&lang=en&cc=us", NULL),
+       B("HP",         "Vectra VL420 SFF",     OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060661&lang=en&cc=us", NULL),
+       B("HP",         "xw4400 (0A68h)",       BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00775230", "ICH7 with SPI lock down, BIOS lock, flash block detection (SST25VF080B); see http://paste.flashrom.org/view.php?id=686"),
+       B("HP",         "xw6400",               BAD, NULL, "No chip found, see http://www.flashrom.org/pipermail/flashrom/2012-March/009006.html"),
+       B("HP",         "xw9300",               BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodTypeId=12454&prodSeriesId=459226", "Missing board enable, see http://www.flashrom.org/pipermail/flashrom/2012-February/008862.html"),
+       B("HP",         "xw9400",               OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodSeriesId=3211286&prodTypeId=12454", "Boot block is write protected unless the solder points next to F2 are shorted."),
+       B("HP",         "Z400 Workstation (0AE4h)", BAD, NULL, "ICH10R with BIOS lock enable and a protected range PRBAD, see http://www.flashrom.org/pipermail/flashrom/2012-June/009350.html"),
+       B("IBASE",      "MB899",                OK, "http://www.ibase-i.com.tw/2009/mb899.html", NULL),
+       B("IBM",        "x3455",                OK, "http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html", NULL),
+       B("IEI",        "PICOe-9452",           OK, "http://www.ieiworld.com/product_groups/industrial/content.aspx?keyword=WSB&gid=00001000010000000001&cid=08125380291060861658&id=08142308605814597144", NULL),
+       B("Intel",      "D201GLY",              OK, "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm", NULL),
+       B("Intel",      "D425KT",               BAD, "http://www.intel.com/content/www/us/en/motherboards/desktop-motherboards/desktop-board-d425kt.html", "NM10 with SPI lock down, BIOS lock, see http://www.flashrom.org/pipermail/flashrom/2012-January/008600.html"),
+       B("Intel",      "D865GLC",              BAD, NULL, "ICH5 with BIOS lock enable, see http://paste.flashrom.org/view.php?id=775"),
+       B("Intel",      "DG45ID",               BAD, "http://www.intel.com/products/desktop/motherboards/dg45id/dg45id-overview.htm", "Probing works (Winbond W25x32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+       B("Intel",      "DQ965GF",              BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF016B, 2048 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
+       B("Intel",      "DG965OT",              BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF080B, 1024 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
+       B("Intel",      "DH61AG ",              BAD, NULL, "H61 with BIOS lock enable and locked ME region, see http://www.flashrom.org/pipermail/flashrom/2012-June/009417.html"),
+       B("Intel",      "DH67CF",               BAD, NULL, "H67 with BIOS lock enable and locked ME region, see http://www.flashrom.org/pipermail/flashrom/2011-September/007789.html"),
+       B("Intel",      "DN2800MT (Marshalltown)", BAD, NULL, "BIOS locked via BIOS_CNTL."),
+       B("Intel",      "EP80759",              OK, NULL, NULL),
+       B("Intel",      "Foxhollow",            OK, NULL, "Intel reference board."),
+       B("Intel",      "Greencity",            OK, NULL, "Intel reference board."),
+       B("Intel",      "SE440BX-2",            BAD, "http://downloadcenter.intel.com/SearchResult.aspx?lang=eng&ProductFamily=Desktop+Boards&ProductLine=Discontinued+Motherboards&ProductProduct=Intel%C2%AE+SE440BX-2+Motherboard", "Probably won't work, see http://www.coreboot.org/pipermail/flashrom/2010-July/003952.html"),
+       B("IWILL",      "DK8-HTX",              OK, "http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98", NULL),
+       B("Jetway",     "J-7BXAN",              OK, "http://www.jetway.com.tw/evisn/download/d7BXAS.htm", NULL),
+       B("Jetway",     "J7F4K1G5D-PB",         OK, "http://www.jetway.com.tw/jw/ipcboard_view.asp?productid=282&proname=J7F4K1G5D", NULL),
+       B("Kontron",    "986LCD-M",             OK, "http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html", NULL),
+       B("Lanner",     "EM-8510C",             OK, NULL, NULL),
+       B("Lex",        "CV700A",               OK, "http://www.lex.com.tw/product/CV700A-spec.htm", NULL),
+       B("Mitac",      "6513WU",               OK, "http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm", NULL),
+       B("MSC",        "Q7-TCTC",              OK, "http://www.msc-ge.com/en/produkte/com/moduls/overview/5779-www.html", NULL),
+       B("MSI",        "MS-6153",              OK, "http://www.msi.com/product/mb/MS-6153.html", NULL),
+       B("MSI",        "MS-6156",              OK, "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm", NULL),
+       B("MSI",        "MS-6163 (MS-6163 Pro)",OK, "http://www.msi.com/product/mb/MS-6163-Pro.html", NULL),
+       B("MSI",        "MS-6178",              BAD, "http://www.msi.com/product/mb/MS-6178.html", "Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot. Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
+       B("MSI",        "MS-6330 (K7T Turbo)",  OK, "http://www.msi.com/product/mb/K7T-Turbo.html", NULL),
+       B("MSI",        "MS-6391 (845 Pro4)",   OK, "http://www.msi.com/product/mb/845-Pro4.html", NULL),
+       B("MSI",        "MS-6561 (745 Ultra)",  OK, "http://www.msi.com/product/mb/745-Ultra.html", NULL),
+       B("MSI",        "MS-6566 (845 Ultra-C)",OK, "http://www.msi.com/product/mb/845-Ultra-C.html", NULL),
+       B("MSI",        "MS-6570 (K7N2)",       OK, "http://www.msi.com/product/mb/K7N2.html", NULL),
+       B("MSI",        "MS-6577 (Xenon)",      OK, "http://h10025.www1.hp.com/ewfrf/wc/document?product=90390&lc=en&cc=us&dlc=en&docname=bph07843", "This is an OEM board from HP, the HP name is Xenon."),
+       B("MSI",        "MS-6590 (KT4 Ultra)",  OK, "http://www.msi.com/product/mb/KT4-Ultra.html", NULL),
+       B("MSI",        "MS-6702E (K8T Neo2-F)",OK, "http://www.msi.com/product/mb/K8T-Neo2-F--FIR.html", NULL),
+       B("MSI",        "MS-6712 (KT4V)",       OK, "http://www.msi.com/product/mb/KT4V---KT4V-L--v1-0-.html", NULL),
+       B("MSI",        "MS-6787 (P4MAM-V/P4MAM-L)", OK, "http://www.msi.com/service/search/?kw=6787&type=product", NULL),
+       B("MSI",        "MS-7005 (651M-L)",     OK, "http://www.msi.com/product/mb/651M-L.html", NULL),
+       B("MSI",        "MS-7025 (K8N Neo2 Platinum)", OK, "http://www.msi.com/product/mb/K8N-Neo2-Platinum.html", NULL),
+       B("MSI",        "MS-7046",              OK, "http://www.heimir.de/ms7046/", NULL),
+       B("MSI",        "MS-7061 (KM4M-V/KM4AM-V)", OK, "http://www.msi.com/service/search/?kw=7061&type=product", NULL),
+       B("MSI",        "MS-7065",              OK, "http://browse.geekbench.ca/geekbench2/view/53114", NULL),
+       B("MSI",        "MS-7135 (K8N Neo3)",   OK, "http://www.msi.com/product/mb/K8N-Neo3.html", NULL),
+       B("MSI",        "MS-7142 (K8MM-V)",     OK, "http://www.msi.com/product/mb/K8MM-V.html", NULL),
+       B("MSI",        "MS-7168 (Orion)",      OK, "http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart", NULL),
+       B("MSI",        "MS-7207 (K8NGM2-L)",   OK, "http://www.msi.com/product/mb/K8NGM2-FID--IL--L.html", NULL),
+       B("MSI",        "MS-7211 (PM8M3-V)",    OK, "http://www.msi.com/product/mb/PM8M3-V.html", NULL),
+       B("MSI",        "MS-7236 (945PL Neo3)", OK, "http://www.msi.com/product/mb/945PL-Neo3.html", NULL),
+       B("MSI",        "MS-7250 (K9N SLI (rev 2.1))", OK, "http://www.msi.com/product/mb/K9N--SLI.html", NULL),
+       B("MSI",        "MS-7253 (K9VGM-V)",    OK, "http://www.msi.com/product/mb/K9VGM-V.html", NULL),
+       B("MSI",        "MS-7255 (P4M890M)",    OK, "http://www.msi.com/product/mb/P4M890M-L-IL.html", NULL),
+       B("MSI",        "MS-7260 (K9N Neo PCB 1.0)", BAD, "http://www.msi.com/product/mb/K9N-Neo--PCB-1-0-.html", "Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot. Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
+       B("MSI",        "MS-7309 (K9N6PGM2-V2)", OK, "http://www.msi.com/product/mb/K9N6PGM2-V2.html", NULL),
+       B("MSI",        "MS-7312 (K9MM-V)",     OK, "http://www.msi.com/product/mb/K9MM-V.html", NULL),
+       B("MSI",        "MS-7345 (P35 Neo2-FIR)", OK, "http://www.msi.com/product/mb/P35-Neo2-FR---FIR.html", NULL),
+       B("MSI",        "MS-7368 (K9AG Neo2-Digital)", OK, "http://www.msi.com/product/mb/K9AG-Neo2-Digital.html", NULL),
+       B("MSI",        "MS-7369 (K9N Neo V2)", OK, "http://www.msi.com/product/mb/K9N-Neo-V2.html", NULL),
+       B("MSI",        "MS-7376 (K9A2 Platinum V1)", OK, "http://www.msi.com/product/mb/K9A2-Platinum.html", NULL),
+       B("MSI",        "MS-7529 (G31M3-L(S) V2)", OK, "http://www.msi.com/product/mb/G31M3-L-V2---G31M3-LS-V2.html", NULL),
+       B("MSI",        "MS-7529 (G31TM-P21)",  OK, "http://www.msi.com/product/mb/G31TM-P21.html", NULL),
+       B("MSI",        "MS-7548 (Aspen-GL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c01635688&lc=en&cc=us&dlc=en", NULL),
+       B("MSI",        "MS-7596 (785GM-E51)",  OK, "http://www.msi.com/product/mb/785GM-E51.html", NULL),
+       B("MSI",        "MS-7597 (GF615M-P33)", BAD, NULL, "Missing board enable/SIO support (Fintek F71889), see http://www.flashrom.org/pipermail/flashrom/2012-March/008956.html"),
+       B("MSI",        "MS-7599 (870-C45)",    OK, "http://www.msi.com/product/mb/870-C45.html", NULL),
+       B("MSI",        "MS-7613 (Iona-GL8E)",  BAD, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c02014355&lc=en&cc=dk&dlc=en&product=4348478", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("MSI",        "MS-7635 (H55M-ED55)",  BAD, "http://www.msi.com/product/mb/H55M-ED55.html", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("MSI",        "MS-7640 (890FXA-GD70)",OK, "http://www.msi.com/product/mb/890FXA-GD70.html", NULL),
+       B("MSI",        "MS-7642 (890GXM-G65)", OK, "http://www.msi.com/product/mb/890GXM-G65.html", NULL),
+       B("MSI",        "MS-7676 (H67MA-ED55(B3))", OK, "http://www.msi.com/product/mb/H67MA-ED55--B3-.html", "Seems to work fine basically, but user reported (hopefully unrelated) buggy behavior of the board after a firmware upgrade. See http://www.flashrom.org/pipermail/flashrom/2012-January/008547.html"),
+       B("MSI",        "MS-7676 (Z68MA-G45 (B3))", OK, "http://www.msi.com/product/mb/Z68MA-G45--B3-.html", NULL),
+       B("MSI",        "MS-7696 (A75MA-G55)",  OK, "http://www.msi.com/product/mb/A75MA-G55.html", NULL),
+       B("MSI",        "MS-7698 (E350IA-E45)", OK, "http://www.msi.com/product/mb/E350IA-E45.html", NULL),
+       B("MSI",        "MS-7740 (H61MA-E35(B3))",      OK, "http://www.msi.com/product/mb/H61MA-E35--B3-.html", NULL),
+       B("NEC",        "PowerMate 2000",       OK, "http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/", NULL),
+       B("Nokia",      "IP530",                OK, NULL, NULL),
+       B("Palit",      "N61S",                 OK, NULL, NULL),
+       B("PCCHIPS ",   "M598LMR (V9.0)",       OK, NULL, NULL),
+       B("PCCHIPS ",   "M863G (V5.1A)",        OK, "http://www.pcchips.com.tw/PCCWebSite/Products/ProductsDetail.aspx?CategoryID=1&DetailID=343&DetailName=Feature&MenuID=1&LanID=0", NULL),
+       B("PC Engines", "Alix.1c",              OK, "http://pcengines.ch/alix1c.htm", NULL),
+       B("PC Engines", "Alix.2c2",             OK, "http://pcengines.ch/alix2c2.htm", NULL),
+       B("PC Engines", "Alix.2c3",             OK, "http://pcengines.ch/alix2c3.htm", NULL),
+       B("PC Engines", "Alix.2d3",             OK, "http://pcengines.ch/alix2d3.htm", NULL),
+       B("PC Engines", "Alix.3c3",             OK, "http://pcengines.ch/alix3c3.htm", NULL),
+       B("PC Engines", "Alix.3d3",             OK, "http://pcengines.ch/alix3d3.htm", NULL),
+       B("PC Engines", "Alix.6f2",             OK, "http://pcengines.ch/alix6f2.htm", NULL),
+       B("PC Engines", "WRAP.2E",              OK, "http://pcengines.ch/wrap2e1.htm", NULL),
+       B("Portwell",   "PEB-4700VLA",          OK, "http://www.portwell.com/products/detail.asp?CUSTCHAR1=PEB-4700VLA", NULL),
+       B("RCA",        "RM4100",               OK, "http://www.settoplinux.org/index.php?title=RCA_RM4100", NULL),
+       B("Samsung",    "Polaris 32",           OK, NULL, NULL),
+       B("Shuttle",    "AK31",                 OK, "http://www.motherboard.cz/mb/shuttle/AK31.htm", NULL),
+       B("Shuttle",    "AK38N",                OK, "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/", NULL),
+       B("Shuttle",    "AV11V30",              OK, NULL, NULL),
+       B("Shuttle",    "AV18E2",               OK, "http://www.shuttle.eu/_archive/older/de/av18.htm", NULL),
+       B("Shuttle",    "FD37",                 OK, "http://www.shuttle.eu/products/discontinued/barebones/sd37p2/", NULL),
+       B("Shuttle",    "FH67",                 OK, "http://www.shuttle.eu/products/mini-pc/sh67h3/specification/", NULL),
+       B("Shuttle",    "FN25",                 OK, "http://www.shuttle.eu/products/discontinued/barebones/sn25p/?0=", NULL),
+       B("Shuttle",    "X50/X50(B)",           OK, "http://au.shuttle.com/product_detail_spec.jsp?PI=1241", NULL),
+       B("Soyo",       "SY-5VD",               BAD, "http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+       B("Soyo",       "SY-6BA+ III",          OK, "http://www.motherboard.cz/mb/soyo/SY-6BA+III.htm", NULL),
+       B("Soyo",       "SY-7VCA",              OK, "http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html", NULL),
+       B("Sun",        "Blade x6250",          OK, "http://www.sun.com/servers/blades/x6250/", NULL),
+       B("Sun",        "Fire x4150",           BAD, "http://www.sun.com/servers/x64/x4150/", "No public report found. May work now."),
+       B("Sun",        "Fire x4200",           BAD, "http://www.sun.com/servers/entry/x4200/", "No public report found. May work now."),
+       B("Sun",        "Fire x4540",           BAD, "http://www.sun.com/servers/x64/x4540/", "No public report found. May work now."),
+       B("Sun",        "Fire x4600",           BAD, "http://www.sun.com/servers/x64/x4600/", "No public report found. May work now."),
+       B("Sun",        "Ultra 40 M2",          OK, "http://download.oracle.com/docs/cd/E19127-01/ultra40.ws/820-0123-13/intro.html", NULL),
+       B("Supermicro", "H8QC8",                OK, "http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm", NULL),
+       B("Supermicro", "X5DP8-G2",             OK, "http://www.supermicro.com/products/motherboard/Xeon/E7501/X5DP8-G2.cfm", NULL),
+       B("Supermicro", "X7DBT-INF",            OK, "http://www.supermicro.com/products/motherboard/Xeon1333/5000P/X7DBT-INF.cfm", NULL),
+       B("Supermicro", "X7SPA-HF",             OK, "http://www.supermicro.com/products/motherboard/ATOM/ICH9/X7SPA.cfm?typ=H&IPMI=Y", NULL),
+       B("Supermicro", "X8DT3",                OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DT3.cfm", NULL),
+       B("Supermicro", "X8DTE-F",              OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DT6-F.cfm?IPMI=Y&SAS=N", NULL),
+       B("Supermicro", "X8DTH-6F",             OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTH-6F.cfm", NULL),
+       B("Supermicro", "X8DTT-F",              OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTT-F.cfm", NULL),
+       B("Supermicro", "X8DTT-HIBQF",          OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTT-H.cfm", NULL),
+       B("Supermicro", "X8DTU-6TF+",           BAD, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTU_.cfm?TYP=SAS&LAN=10", "Probing works (Atmel AT25DF321A, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("Supermicro", "X8DTU-F",              OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTU-F.cfm", NULL),
+       B("Supermicro", "X8SIE(-F)",            BAD, "http://www.supermicro.com/products/motherboard/Xeon3000/3400/X8SIE.cfm?IPMI=N&TYP=LN2", "Requires unlocking the ME although the registers are set up correctly by the descriptor/BIOS already (tested with swseq and hwseq)."),
+       B("Supermicro", "X8STi",                OK, "http://www.supermicro.com/products/motherboard/Xeon3000/X58/X8STi.cfm", NULL),
+       B("Supermicro", "X9DR3-F",              BAD, "http://www.supermicro.com/products/motherboard/xeon/c600/x9dr3-f.cfm", "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("Supermicro", "X9SCA-F",              BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCA-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("Supermicro", "X9SCL",                BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCL.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("T-Online",   "S-100",                OK, "http://wiki.freifunk-hannover.de/T-Online_S_100", NULL),
+       B("Tekram",     "P6Pro-A5",             OK, "http://www.motherboard.cz/mb/tekram/P6Pro-A5.htm", NULL),
+       B("Termtek",    "TK-3370 (Rev:2.5B)",   OK, NULL, NULL),
+       B("Thomson",    "IP1000",               OK, "http://www.settoplinux.org/index.php?title=Thomson_IP1000", NULL),
+       B("TriGem",     "Anaheim-3",            OK, "http://www.e4allupgraders.info/dir1/motherboards/socket370/anaheim3.shtml", NULL),
+       B("TriGem",     "Lomita",               OK, "http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml", NULL),
+       B("Tyan",       "S1846 (Tsunami ATX)",  OK, "http://www.tyan.com/archive/products/html/tsunamiatx.html", NULL),
+       B("Tyan",       "S2466 (Tiger MPX)",    OK, "http://www.tyan.com/product_board_detail.aspx?pid=461", NULL),
+       B("Tyan",       "S2498 (Tomcat K7M)",   OK, "http://www.tyan.com/archive/products/html/tomcatk7m.html", NULL),
+       B("Tyan",       "S2723 (Tiger i7501)",  OK, "http://www.tyan.com/archive/products/html/tigeri7501.html", NULL),
+       B("Tyan",       "S2875 (Tiger K8W)",    OK, "http://www.tyan.com/archive/products/html/tigerk8w.html", NULL),
+       B("Tyan",       "S2881 (Thunder K8SR)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=115", NULL),
+       B("Tyan",       "S2882-D (Thunder K8SD Pro)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=127", NULL),
+       B("Tyan",       "S2882 (Thunder K8S Pro)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=121", NULL),
+       B("Tyan",       "S2891 (Thunder K8SRE)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=144", NULL),
+       B("Tyan",       "S2892 (Thunder K8SE)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=145", NULL),
+       B("Tyan",       "S2895 (Thunder K8WE)", OK, "http://www.tyan.com/archive/products/html/thunderk8we.html", NULL),
+       B("Tyan",       "S2912 (Thunder n3600R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=157", NULL),
+       B("Tyan",       "S2915-E (Thunder n6650W)", OK, "http://tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=541&SKU=600000041", NULL),
+       B("Tyan",       "S2915 (Thunder n6650W)", OK, "http://tyan.com/product_board_detail.aspx?pid=163", NULL),
+       B("Tyan",       "S2933 (Thunder n3600S)", OK, "http://tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=478&SKU=600000063", NULL),
+       B("Tyan",       "S3095 (Tomcat i945GM)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=181", NULL),
+       B("Tyan",       "S3992 (Thunder h2000M)", OK, "http://tyan.com/product_board_detail.aspx?pid=235", NULL),
+       B("Tyan",       "S5180 (Toledo i965R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=456", NULL),
+       B("Tyan",       "S5191 (Toledo i3000R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=343", NULL),
+       B("Tyan",       "S5197 (Toledo i3010W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=349", NULL),
+       B("Tyan",       "S5211-1U (Toledo i3200R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=593", NULL),
+       B("Tyan",       "S5211 (Toledo i3210W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=591", NULL),
+       B("Tyan",       "S5220 (Toledo q35T)",  OK, "http://www.tyan.com/product_board_detail.aspx?pid=597", NULL),
+       B("Tyan",       "S5375-1U (Tempest i5100X)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=610", NULL),
+       B("Tyan",       "S5375 (Tempest i5100X)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=566", NULL),
+       B("Tyan",       "S5376 (Tempest i5100W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=605", "Both S5376G2NR and S5376WAG2NR should work."),
+       B("Tyan",       "S5377 (Tempest i5100T)", OK, "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017", NULL),
+       B("Tyan",       "S5382 (Tempest i5000PW)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=439", NULL),
+       B("Tyan",       "S5397 (Tempest i5400PW)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=560", NULL),
+       B("VIA",        "EPIA M/MII/...",       OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202", NULL), /* EPIA-MII link for now */
+       B("VIA",        "EPIA SP",              OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261", NULL),
+       B("VIA",        "EPIA-CN",              OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400", NULL),
+       B("VIA",        "EPIA EK",              OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?motherboard_id=420", NULL),
+       B("VIA",        "EPIA-EX15000G",        OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450", NULL),
+       B("VIA",        "EPIA-LN",              OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473", NULL),
+       B("VIA",        "EPIA-M700",            OK, "http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700", NULL),
+       B("VIA",        "EPIA-N/NL",            OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221", NULL), /* EPIA-N link for now */
+       B("VIA",        "EPIA-NX15000G",        OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470", NULL),
+       B("VIA",        "NAB74X0",              OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590", NULL),
+       B("VIA",        "pc2500e",              OK, "http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp", NULL),
+       B("VIA",        "PC3500G",              OK, "http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp", NULL),
+       B("VIA",        "VB700X",               OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490", NULL),
+       B("ZOTAC",      "Fusion-ITX WiFi (FUSION350-A-E)", OK, NULL, NULL),
+       B("ZOTAC",      "GeForce 8200",         OK, NULL, NULL),
+       B("ZOTAC",      "H67-ITX WiFi (H67ITX-C-E)", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("ZOTAC",      "nForce 630i Supreme (N73U-Supreme)", OK, NULL, NULL),
+       B("ZOTAC",      "ZBOX AD02 (PLUS)",     OK, NULL, NULL),
+       B("ZOTAC",      "ZBOX HD-ID11",         OK, NULL, NULL),
+#endif
+
+       {},
+};
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info laptops_known[] = {
+#if defined(__i386__) || defined(__x86_64__)
+       B("Acer",       "Aspire 1520",          OK, "http://support.acer.com/us/en/acerpanam/notebook/0000/Acer/Aspire1520/Aspire1520nv.shtml", NULL),
+       B("Acer",       "Aspire One",           BAD, NULL, "http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html"),
+       B("ASUS",       "A8Jm",                 OK, NULL, NULL),
+       B("ASUS",       "Eee PC 701 4G",        BAD, "http://www.asus.com/Eee/Eee_PC/Eee_PC_4G/", "It seems the chip (25X40VSIG) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)."),
+       B("ASUS",       "M6Ne",                 NT, "http://www.asus.com/Notebooks/Versatile_Performance/M6NNe/", "Untested board enable."),
+       B("Clevo",      "P150HM",               BAD, "http://www.clevo.com.tw/en/products/prodinfo_2.asp?productid=307", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+       B("Dell",       "Inspiron 1420",        OK, NULL, NULL),
+       B("Dell",       "Latitude CPi A366XT",  BAD, "http://www.coreboot.org/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."),
+       B("Dell",       "Vostro 3700",          BAD, NULL, "Locked ME, see http://www.flashrom.org/pipermail/flashrom/2012-May/009197.html."),
+       B("Dell",       "Latitude E6520",       BAD, NULL, "Locked ME, see http://www.flashrom.org/pipermail/flashrom/2012-June/009420.html."),
+       B("HP/Compaq",  "nx9005",               BAD, "http://h18000.www1.hp.com/products/quickspecs/11602_na/11602_na.HTML", "Shuts down when probing for a chip. http://www.flashrom.org/pipermail/flashrom/2010-May/003321.html"),
+       B("HP/Compaq",  "nx9010",               BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)."),
+       B("IBM/Lenovo", "Thinkpad T40p",        BAD, "http://www.thinkwiki.org/wiki/Category:T40p", NULL),
+       B("IBM/Lenovo", "Thinkpad T420",        BAD, "http://www.thinkwiki.org/wiki/Category:T420", "Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
+       B("IBM/Lenovo", "Thinkpad T410s",       BAD, "http://www.thinkwiki.org/wiki/Category:T410s", "Probing works (Winbond W25X64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
+       B("IBM/Lenovo", "Thinkpad X1",          BAD, "http://www.thinkwiki.org/wiki/Category:X1", "Probing works (ST M25PX64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
+       B("IBM/Lenovo", "240",                  BAD, "http://www.stanford.edu/~bresnan//tp240.html", "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."),
+       B("Lenovo",     "3000 V100 TF05Cxx",    OK, "http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop", NULL),
+#endif
+
+       {},
+};
+#endif
diff --git a/print_wiki.c b/print_wiki.c
new file mode 100644 (file)
index 0000000..617053c
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "flash.h"
+#include "flashchips.h"
+#include "programmer.h"
+
+static const char wiki_header[] = "= Supported devices =\n\n\
+<div style=\"margin-top:0.5em; padding:0.5em 0.5em 0.5em 0.5em; \
+background-color:#eeeeee; text-align:right; border:1px solid #aabbcc;\">\
+<small>\n\
+Please do '''not''' edit these tables in the wiki directly, they are \
+generated by pasting '''flashrom -z''' output.<br />\
+'''Last update:''' %s(generated by flashrom %s)\n</small></div>\n";
+
+static const char th_start[] = "| valign=\"top\"|\n\n\
+{| border=\"0\" style=\"font-size: smaller\" valign=\"top\"\n\
+|- bgcolor=\"#6699dd\"\n";
+
+#if CONFIG_INTERNAL == 1
+static const char chipset_th[] = "\
+! align=\"left\" | Vendor\n\
+! align=\"left\" | Southbridge\n\
+! align=\"center\" | PCI IDs\n\
+! align=\"center\" | Status\n\n";
+
+static const char board_th[] = "\
+! align=\"left\" | Vendor\n\
+! align=\"left\" | Mainboard\n\
+! align=\"left\" | Required option\n\
+! align=\"center\" | Status\n\n";
+
+static 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 (or individual revisions) 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";
+#endif
+
+static const char chip_th[] = "\
+! align=\"left\" | Vendor\n\
+! align=\"left\" | Device\n\
+! align=\"center\" | Size [kB]\n\
+! align=\"center\" | Type\n\
+! align=\"center\" colspan=\"4\" | Status\n\
+! align=\"center\" colspan=\"2\" | Voltage [V]\n\n\
+|- bgcolor=\"#6699ff\"\n| colspan=\"4\" | &nbsp;\n\
+| Probe\n| Read\n| Erase\n| Write\n\
+| align=\"center\" | Min \n| align=\"center\" | Max\n\n";
+
+static const char programmer_th[] = "\
+! align=\"left\" | Vendor\n\
+! align=\"left\" | Device\n\
+! align=\"center\" | PCI IDs\n\
+! align=\"center\" | Status\n\n";
+
+static const char programmer_intro[] = "\
+\n== Supported programmers ==\n\n\
+This is a list of supported PCI devices flashrom can use as programmer:\n\n{";
+
+#if CONFIG_INTERNAL == 1
+static 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\
+<div style=\"margin-top:0.5em; padding:0.5em 0.5em 0.5em 0.5em; \
+background-color:#ff6666; align:right; border:1px solid #000000;\">\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</div>\n";
+
+static void print_supported_chipsets_wiki(int cols)
+{
+       int i;
+       unsigned int lines_per_col;
+       const struct penable *e;
+       int enablescount = 0, color = 1;
+
+       for (e = chipset_enables; e->vendor_name != NULL; e++)
+               enablescount++;
+
+       /* +1 to force the resulting number of columns to be < cols */
+       lines_per_col = enablescount / cols + ((enablescount%cols) > 0 ? 1 : 0);
+
+       printf("\n== Supported chipsets ==\n\nTotal amount of supported chipsets: '''%d'''\n\n"
+              "{| border=\"0\" valign=\"top\"\n", enablescount);
+
+       e = chipset_enables;
+       for (i = 0; e[i].vendor_name != NULL; i++) {
+               if ((i % lines_per_col) == 0)
+                       printf("%s%s", th_start, chipset_th);
+
+               /* Alternate colors if the vendor changes. */
+               if (i > 0 && strcmp(e[i].vendor_name, e[i - 1].vendor_name))
+                       color = !color;
+
+               printf("|- bgcolor=\"#%s\"\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}}" : "{{?3}}");
+
+               if (((i % lines_per_col) + 1) == lines_per_col)
+                       printf("\n|}\n\n");
+       }
+
+       /* end inner table if it did not fill the last column fully */
+       if (((i % lines_per_col)) > 0)
+               printf("\n|}\n\n");
+       printf("\n\n|}\n");
+}
+
+static void wiki_helper(const char *devicetype, int cols, const struct board_info boards[])
+{
+       int i, k;
+       unsigned int boardcount, lines_per_col;
+       unsigned int boardcount_good = 0, boardcount_bad = 0, boardcount_nt = 0;
+       int num_notes = 0, color = 1;
+       char *notes = calloc(1, 1);
+       char tmp[900 + 1];
+       const struct board_match *b = board_matches;
+
+       for (i = 0; boards[i].vendor != NULL; i++) {
+               if (boards[i].working == OK)
+                       boardcount_good++;
+               else if (boards[i].working == NT)
+                       boardcount_nt++;
+               else
+                       boardcount_bad++;
+       }
+       boardcount = boardcount_good + boardcount_nt + boardcount_bad;
+
+       /* +1 to force the resulting number of columns to be < cols */
+       lines_per_col = boardcount / cols + ((boardcount%cols) > 0 ? 1 : 0);
+
+       printf("\n\nTotal amount of known good boards %s: '''%d'''; "
+              "Untested (e.g. user vanished before testing new code): '''%d'''; "
+              "Not yet supported (i.e. known-bad): '''%d'''.\n\n"
+              "{| border=\"0\" valign=\"top\"\n", devicetype, boardcount_good, boardcount_nt, boardcount_bad);
+
+       for (i = 0; boards[i].vendor != NULL; i++) {
+               if ((i % lines_per_col) == 0)
+                       printf("%s%s", th_start, board_th);
+
+               /* Alternate colors if the vendor changes. */
+               if (i > 0 && strcmp(boards[i].vendor, boards[i - 1].vendor))
+                       color = !color;
+
+               k = 0;
+               while ((b[k].vendor_name != NULL) &&
+                       (strcmp(b[k].vendor_name, boards[i].vendor) ||
+                        strcmp(b[k].board_name, boards[i].name))) {
+                       k++;
+               }
+
+               printf("|- bgcolor=\"#%s\"\n| %s || %s%s %s%s || %s%s%s%s "
+                      "|| {{%s}}", (color) ? "eeeeee" : "dddddd",
+                      boards[i].vendor,
+                      boards[i].url ? "[" : "",
+                      boards[i].url ? boards[i].url : "",
+                      boards[i].name,
+                      boards[i].url ? "]" : "",
+                      b[k].lb_vendor ? "-p internal:mainboard=" : "&mdash;",
+                      b[k].lb_vendor ? b[k].lb_vendor : "",
+                      b[k].lb_vendor ? ":" : "",
+                      b[k].lb_vendor ? b[k].lb_part : "",
+                      (boards[i].working == OK) ? "OK" :
+                      (boards[i].working == NT) ? "?3" : "No");
+
+               if (boards[i].note) {
+                       printf("<sup>%d</sup>\n", num_notes + 1);
+                       snprintf(tmp, sizeof(tmp), "<sup>%d</sup> %s<br />\n",
+                                1 + num_notes++, boards[i].note);
+                       notes = strcat_realloc(notes, tmp);
+               } else {
+                       printf("\n");
+               }
+
+               if (((i % lines_per_col) + 1) == lines_per_col)
+                       printf("\n|}\n\n");
+       }
+
+       /* end inner table if it did not fill the last column fully */
+       if (((i % lines_per_col)) > 0)
+               printf("\n|}\n\n");
+       printf("\n\n|}\n");
+
+       if (num_notes > 0)
+               printf("\n<small>\n%s</small>\n", notes);
+       free(notes);
+}
+
+static void print_supported_boards_wiki(void)
+{
+       printf("%s", board_intro);
+       wiki_helper("boards", 2, boards_known);
+
+       printf("%s", laptop_intro);
+       wiki_helper("laptops", 1, laptops_known);
+}
+#endif
+
+static void print_supported_chips_wiki(int cols)
+{
+       unsigned int lines_per_col;
+       uint32_t t;
+       char *s;
+       char vmax[6];
+       char vmin[6];
+       const struct flashchip *f, *old = NULL;
+       int i = 0, c = 1, chipcount = 0;
+
+       for (f = flashchips; f->name != NULL; f++) {
+               /* Don't count generic entries. */
+               if (!strncmp(f->vendor, "Unknown", 7) ||
+                   !strncmp(f->vendor, "Programmer", 10) ||
+                   !strncmp(f->name, "unknown", 7))
+                       continue;
+               chipcount++;
+       }
+
+       /* +1 to force the resulting number of columns to be < cols */
+       lines_per_col = chipcount / cols + ((chipcount%cols) > 0 ? 1 : 0);
+
+       printf("\n== Supported chips ==\n\nTotal amount of supported chips: '''%d'''\n\n"
+              "{| border=\"0\" valign=\"top\"\n", chipcount);
+
+       for (f = flashchips; f->name != NULL; f++) {
+               /* Don't print generic entries. */
+               if (!strncmp(f->vendor, "Unknown", 7) ||
+                   !strncmp(f->vendor, "Programmer", 10) ||
+                   !strncmp(f->name, "unknown", 7))
+                       continue;
+
+               if ((i % lines_per_col) == 0)
+                       printf("%s%s", th_start, chip_th);
+
+               /* Alternate colors if the vendor changes. */
+               if (old != NULL && strcmp(old->vendor, f->vendor))
+                       c = !c;
+
+               old = f;
+               t = f->tested;
+               s = flashbuses_to_text(f->bustype);
+               sprintf(vmin, "%0.03f", f->voltage.min / (double)1000);
+               sprintf(vmax, "%0.03f", f->voltage.max / (double)1000);
+               /* '{{%s}}' is used in combination with 'OK', 'No' and '?3' to
+                * select special formatting templates for the bg color. */
+               printf("|- bgcolor=\"#%s\"\n| %s || %s || align=\"right\" | %d "
+                      "|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}"
+                      "|| %s || %s \n",
+                      (c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name,
+                      f->total_size, s,
+                      (t & TEST_OK_PROBE) ? "OK" :
+                      (t & TEST_BAD_PROBE) ? "No" : "?3",
+                      (t & TEST_OK_READ) ? "OK" :
+                      (t & TEST_BAD_READ) ? "No" : "?3",
+                      (t & TEST_OK_ERASE) ? "OK" :
+                      (t & TEST_BAD_ERASE) ? "No" : "?3",
+                      (t & TEST_OK_WRITE) ? "OK" :
+                      (t & TEST_BAD_WRITE) ? "No" : "?3",
+                      f->voltage.min ? vmin : "N/A",
+                      f->voltage.min ? vmax : "N/A");
+               free(s);
+
+               if (((i % lines_per_col) + 1) == lines_per_col)
+                       printf("\n|}\n\n");
+               i++;
+       }
+       /* end inner table if it did not fill the last column fully */
+       if (((i % lines_per_col)) > 0)
+               printf("\n|}\n\n");
+       printf("|}\n\n");
+}
+
+/* Not needed for CONFIG_INTERNAL, but for all other PCI-based programmers. */
+#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_NICINTEL+CONFIG_NICINTEL_SPI+CONFIG_OGP_SPI+CONFIG_SATAMV >= 1
+static void print_supported_pcidevs_wiki(const 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\"\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) ? "?3" : "OK");
+       }
+}
+#endif
+
+void print_supported_wiki(void)
+{
+       time_t t = time(NULL);
+
+       printf(wiki_header, ctime(&t), flashrom_version);
+       print_supported_chips_wiki(2);
+#if CONFIG_INTERNAL == 1
+       print_supported_chipsets_wiki(3);
+       print_supported_boards_wiki();
+#endif
+       printf("%s%s%s", programmer_intro, th_start, programmer_th);
+
+#if CONFIG_NIC3COM == 1
+       print_supported_pcidevs_wiki(nics_3com);
+#endif
+#if CONFIG_NICREALTEK == 1
+       print_supported_pcidevs_wiki(nics_realtek);
+#endif
+#if CONFIG_NICNATSEMI == 1
+       print_supported_pcidevs_wiki(nics_natsemi);
+#endif
+#if CONFIG_GFXNVIDIA == 1
+       print_supported_pcidevs_wiki(gfx_nvidia);
+#endif
+#if CONFIG_DRKAISER == 1
+       print_supported_pcidevs_wiki(drkaiser_pcidev);
+#endif
+#if CONFIG_SATASII == 1
+       print_supported_pcidevs_wiki(satas_sii);
+#endif
+#if CONFIG_ATAHPT == 1
+       print_supported_pcidevs_wiki(ata_hpt);
+#endif
+#if CONFIG_NICINTEL == 1
+       print_supported_pcidevs_wiki(nics_intel);
+#endif
+#if CONFIG_NICINTEL_SPI == 1
+       print_supported_pcidevs_wiki(nics_intel_spi);
+#endif
+#if CONFIG_OGP_SPI == 1
+       print_supported_pcidevs_wiki(ogp_spi);
+#endif
+#if CONFIG_SATAMV == 1
+       print_supported_pcidevs_wiki(satas_mv);
+#endif
+       printf("\n|}\n\n|}\n");
+}
+
diff --git a/processor_enable.c b/processor_enable.c
new file mode 100644 (file)
index 0000000..d680f97
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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
+ */
+
+/*
+ * Contains the processor specific flash enables and system settings.
+ */
+
+#include "flash.h"
+#include "programmer.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+
+int processor_flash_enable(void)
+{
+       /* On x86, flash access is not processor specific except on
+        * AMD Elan SC520, AMD Geode and maybe other SoC-style CPUs.
+        * FIXME: Move enable_flash_cs5536 and get_flashbase_sc520 here.
+        */
+       return 0;
+}
+
+#else
+
+#if defined (__MIPSEL__) && defined (__linux)
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+static int is_loongson(void)
+{
+       FILE *cpuinfo;
+       cpuinfo = fopen("/proc/cpuinfo", "rb");
+       if (!cpuinfo)
+               return 0;
+       while (!feof(cpuinfo)) {
+               char line[512], *ptr;
+               if (fgets(line, sizeof(line), cpuinfo) == NULL)
+                       break;
+               ptr = line;
+               while (*ptr && isspace((unsigned char)*ptr))
+                       ptr++;
+               /* "cpu" part appears only with some Linux versions.  */
+               if (strncmp(ptr, "cpu", strlen("cpu")) == 0)
+                       ptr += strlen("cpu");
+               while (*ptr && isspace((unsigned char)*ptr))
+                       ptr++;
+               if (strncmp(ptr, "model", strlen("model")) != 0)
+                       continue;
+               ptr += strlen("model");
+               while (*ptr && isspace((unsigned char)*ptr))
+                       ptr++;
+               if (*ptr != ':')
+                       continue;
+               ptr++;
+               while (*ptr && isspace((unsigned char)*ptr))
+                       ptr++;
+               fclose(cpuinfo);
+               return (strncmp(ptr, "ICT Loongson-2 V0.3",
+                               strlen("ICT Loongson-2 V0.3")) == 0)
+                   || (strncmp(ptr, "Godson2 V0.3  FPU V0.1",
+                               strlen("Godson2 V0.3  FPU V0.1")) == 0);
+       }
+       fclose(cpuinfo);
+       return 0;
+}
+#endif
+
+int processor_flash_enable(void)
+{
+       /* FIXME: detect loongson on FreeBSD and OpenBSD as well.  */
+#if defined (__MIPSEL__) && defined (__linux)
+       if (is_loongson()) {
+               flashbase = 0x1fc00000;
+               return 0;
+       }
+#endif
+       /* Not implemented yet. Oh well. */
+       return 1;
+}
+
+#endif
diff --git a/programmer.c b/programmer.c
new file mode 100644 (file)
index 0000000..3b4def0
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009,2010,2011 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 "flash.h"
+#include "programmer.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 NULL;
+}
+
+/* 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 parallel style drivers not supporting writes */
+void noop_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+}
+
+/* Little-endian fallback for drivers not supporting 16 bit accesses */
+void fallback_chip_writew(const struct flashctx *flash, uint16_t val,
+                         chipaddr addr)
+{
+       chip_writeb(flash, val & 0xff, addr);
+       chip_writeb(flash, (val >> 8) & 0xff, addr + 1);
+}
+
+/* Little-endian fallback for drivers not supporting 16 bit accesses */
+uint16_t fallback_chip_readw(const struct flashctx *flash, const chipaddr addr)
+{
+       uint16_t val;
+       val = chip_readb(flash, addr);
+       val |= chip_readb(flash, addr + 1) << 8;
+       return val;
+}
+
+/* Little-endian fallback for drivers not supporting 32 bit accesses */
+void fallback_chip_writel(const struct flashctx *flash, uint32_t val,
+                         chipaddr addr)
+{
+       chip_writew(flash, val & 0xffff, addr);
+       chip_writew(flash, (val >> 16) & 0xffff, addr + 2);
+}
+
+/* Little-endian fallback for drivers not supporting 32 bit accesses */
+uint32_t fallback_chip_readl(const struct flashctx *flash, const chipaddr addr)
+{
+       uint32_t val;
+       val = chip_readw(flash, addr);
+       val |= chip_readw(flash, addr + 2) << 16;
+       return val;
+}
+
+void fallback_chip_writen(const struct flashctx *flash, uint8_t *buf,
+                         chipaddr addr, size_t len)
+{
+       size_t i;
+       for (i = 0; i < len; i++)
+               chip_writeb(flash, buf[i], addr + i);
+       return;
+}
+
+void fallback_chip_readn(const struct flashctx *flash, uint8_t *buf,
+                        chipaddr addr, size_t len)
+{
+       size_t i;
+       for (i = 0; i < len; i++)
+               buf[i] = chip_readb(flash, addr + i);
+       return;
+}
+
+int register_par_programmer(const struct par_programmer *pgm,
+                           const enum chipbustype buses)
+{
+       struct registered_programmer rpgm;
+       if (!pgm->chip_writeb || !pgm->chip_writew || !pgm->chip_writel ||
+           !pgm->chip_writen || !pgm->chip_readb || !pgm->chip_readw ||
+           !pgm->chip_readl || !pgm->chip_readn) {
+               msg_perr("%s called with incomplete programmer definition. "
+                        "Please report a bug at flashrom@flashrom.org\n",
+                        __func__);
+               return ERROR_FLASHROM_BUG;
+       }
+
+       rpgm.buses_supported = buses;
+       rpgm.par = *pgm;
+       return register_programmer(&rpgm);
+}
+
+/* The limit of 4 is totally arbitrary. */
+#define PROGRAMMERS_MAX 4
+struct registered_programmer registered_programmers[PROGRAMMERS_MAX];
+int registered_programmer_count = 0;
+
+/* This function copies the struct registered_programmer parameter. */
+int register_programmer(struct registered_programmer *pgm)
+{
+       if (registered_programmer_count >= PROGRAMMERS_MAX) {
+               msg_perr("Tried to register more than %i programmer "
+                        "interfaces.\n", PROGRAMMERS_MAX);
+               return ERROR_FLASHROM_LIMIT;
+       }
+       registered_programmers[registered_programmer_count] = *pgm;
+       registered_programmer_count++;
+
+       return 0;
+}
+
+enum chipbustype get_buses_supported(void)
+{
+       int i;
+       enum chipbustype ret = BUS_NONE;
+
+       for (i = 0; i < registered_programmer_count; i++)
+               ret |= registered_programmers[i].buses_supported;
+
+       return ret;
+}
diff --git a/programmer.h b/programmer.h
new file mode 100644 (file)
index 0000000..5109ed9
--- /dev/null
@@ -0,0 +1,682 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
+ * Copyright (C) 2005-2009 coresystems GmbH
+ * Copyright (C) 2006-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
+ */
+
+#ifndef __PROGRAMMER_H__
+#define __PROGRAMMER_H__ 1
+
+#include "flash.h"     /* for chipaddr and flashctx */
+
+enum programmer {
+#if CONFIG_INTERNAL == 1
+       PROGRAMMER_INTERNAL,
+#endif
+#if CONFIG_DUMMY == 1
+       PROGRAMMER_DUMMY,
+#endif
+#if CONFIG_NIC3COM == 1
+       PROGRAMMER_NIC3COM,
+#endif
+#if CONFIG_NICREALTEK == 1
+       PROGRAMMER_NICREALTEK,
+#endif
+#if CONFIG_NICNATSEMI == 1
+       PROGRAMMER_NICNATSEMI,
+#endif
+#if CONFIG_GFXNVIDIA == 1
+       PROGRAMMER_GFXNVIDIA,
+#endif
+#if CONFIG_DRKAISER == 1
+       PROGRAMMER_DRKAISER,
+#endif
+#if CONFIG_SATASII == 1
+       PROGRAMMER_SATASII,
+#endif
+#if CONFIG_ATAHPT == 1
+       PROGRAMMER_ATAHPT,
+#endif
+#if CONFIG_FT2232_SPI == 1
+       PROGRAMMER_FT2232_SPI,
+#endif
+#if CONFIG_SERPROG == 1
+       PROGRAMMER_SERPROG,
+#endif
+#if CONFIG_BUSPIRATE_SPI == 1
+       PROGRAMMER_BUSPIRATE_SPI,
+#endif
+#if CONFIG_DEDIPROG == 1
+       PROGRAMMER_DEDIPROG,
+#endif
+#if CONFIG_RAYER_SPI == 1
+       PROGRAMMER_RAYER_SPI,
+#endif
+#if CONFIG_PONY_SPI == 1
+       PROGRAMMER_PONY_SPI,
+#endif
+#if CONFIG_NICINTEL == 1
+       PROGRAMMER_NICINTEL,
+#endif
+#if CONFIG_NICINTEL_SPI == 1
+       PROGRAMMER_NICINTEL_SPI,
+#endif
+#if CONFIG_OGP_SPI == 1
+       PROGRAMMER_OGP_SPI,
+#endif
+#if CONFIG_SATAMV == 1
+       PROGRAMMER_SATAMV,
+#endif
+#if CONFIG_LINUX_SPI == 1
+       PROGRAMMER_LINUX_SPI,
+#endif
+       PROGRAMMER_INVALID /* This must always be the last entry. */
+};
+
+struct programmer_entry {
+       const char *vendor;
+       const char *name;
+
+       int (*init) (void);
+
+       void *(*map_flash_region) (const char *descr, unsigned long phys_addr,
+                                  size_t len);
+       void (*unmap_flash_region) (void *virt_addr, size_t len);
+
+       void (*delay) (int usecs);
+};
+
+extern const struct programmer_entry programmer_table[];
+
+int programmer_init(enum programmer prog, char *param);
+int programmer_shutdown(void);
+
+enum bitbang_spi_master_type {
+       BITBANG_SPI_INVALID     = 0, /* This must always be the first entry. */
+#if CONFIG_RAYER_SPI == 1
+       BITBANG_SPI_MASTER_RAYER,
+#endif
+#if CONFIG_PONY_SPI == 1
+       BITBANG_SPI_MASTER_PONY,
+#endif
+#if CONFIG_NICINTEL_SPI == 1
+       BITBANG_SPI_MASTER_NICINTEL,
+#endif
+#if CONFIG_INTERNAL == 1
+#if defined(__i386__) || defined(__x86_64__)
+       BITBANG_SPI_MASTER_MCP,
+#endif
+#endif
+#if CONFIG_OGP_SPI == 1
+       BITBANG_SPI_MASTER_OGP,
+#endif
+};
+
+struct bitbang_spi_master {
+       enum bitbang_spi_master_type type;
+
+       /* Note that CS# is active low, so val=0 means the chip is active. */
+       void (*set_cs) (int val);
+       void (*set_sck) (int val);
+       void (*set_mosi) (int val);
+       int (*get_miso) (void);
+       void (*request_bus) (void);
+       void (*release_bus) (void);
+       /* Length of half a clock period in usecs. */
+       unsigned int half_period;
+};
+
+#if CONFIG_INTERNAL == 1
+struct pci_dev;
+struct penable {
+       uint16_t vendor_id;
+       uint16_t device_id;
+       const enum test_state status;
+       const char *vendor_name;
+       const char *device_name;
+       int (*doit) (struct pci_dev *dev, const char *name);
+};
+
+extern const struct penable chipset_enables[];
+
+enum board_match_phase {
+       P1,
+       P2,
+       P3
+};
+
+struct board_match {
+       /* Any device, but make it sensible, like the ISA bridge. */
+       uint16_t first_vendor;
+       uint16_t first_device;
+       uint16_t first_card_vendor;
+       uint16_t first_card_device;
+
+       /* Any device, but make it sensible, like
+        * the host bridge. May be NULL.
+        */
+       uint16_t second_vendor;
+       uint16_t second_device;
+       uint16_t second_card_vendor;
+       uint16_t second_card_device;
+
+       /* Pattern to match DMI entries. May be NULL. */
+       const char *dmi_pattern;
+
+       /* The vendor / part name from the coreboot table. May be NULL. */
+       const char *lb_vendor;
+       const char *lb_part;
+
+       enum board_match_phase phase;
+
+       const char *vendor_name;
+       const char *board_name;
+
+       int max_rom_decode_parallel;
+       const enum test_state status;
+       int (*enable) (void); /* May be NULL. */
+};
+
+extern const struct board_match board_matches[];
+
+struct board_info {
+       const char *vendor;
+       const char *name;
+       const enum test_state working;
+#ifdef CONFIG_PRINT_WIKI
+       const char *url;
+       const char *note;
+#endif
+};
+
+extern const struct board_info boards_known[];
+extern const struct board_info laptops_known[];
+#endif
+
+/* udelay.c */
+void myusec_delay(int usecs);
+void myusec_calibrate_delay(void);
+void internal_delay(int usecs);
+
+#if NEED_PCI == 1
+/* pcidev.c */
+// FIXME: These need to be local, not global
+extern uint32_t io_base_addr;
+extern struct pci_access *pacc;
+extern struct pci_dev *pcidev_dev;
+struct pcidev_status {
+       uint16_t vendor_id;
+       uint16_t device_id;
+       const enum test_state status;
+       const char *vendor_name;
+       const char *device_name;
+};
+uintptr_t pcidev_readbar(struct pci_dev *dev, int bar);
+uintptr_t pcidev_init(int bar, const struct pcidev_status *devs);
+/* rpci_write_* are reversible writes. The original PCI config space register
+ * contents will be restored on shutdown.
+ */
+int rpci_write_byte(struct pci_dev *dev, int reg, uint8_t data);
+int rpci_write_word(struct pci_dev *dev, int reg, uint16_t data);
+int rpci_write_long(struct pci_dev *dev, int reg, uint32_t data);
+#endif
+
+/* print.c */
+#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_NICINTEL+CONFIG_NICINTEL_SPI+CONFIG_OGP_SPI+CONFIG_SATAMV >= 1
+void print_supported_pcidevs(const struct pcidev_status *devs);
+#endif
+
+#if CONFIG_INTERNAL == 1
+/* board_enable.c */
+void w836xx_ext_enter(uint16_t port);
+void w836xx_ext_leave(uint16_t port);
+void probe_superio_winbond(void);
+int it8705f_write_enable(uint8_t port);
+uint8_t sio_read(uint16_t port, uint8_t reg);
+void sio_write(uint16_t port, uint8_t reg, uint8_t data);
+void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask);
+void board_handle_before_superio(void);
+void board_handle_before_laptop(void);
+int board_flash_enable(const char *vendor, const char *part);
+
+/* chipset_enable.c */
+int chipset_flash_enable(void);
+
+/* processor_enable.c */
+int processor_flash_enable(void);
+#endif
+
+/* 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);
+#if CONFIG_INTERNAL == 1
+int setup_cpu_msr(int cpu);
+void cleanup_cpu_msr(void);
+
+/* cbtable.c */
+void lb_vendor_dev_from_string(const 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 */
+struct superio {
+       uint16_t vendor;
+       uint16_t port;
+       uint16_t model;
+};
+extern struct superio superios[];
+extern int superio_count;
+#define SUPERIO_VENDOR_NONE    0x0
+#define SUPERIO_VENDOR_ITE     0x1
+#define SUPERIO_VENDOR_WINBOND 0x2
+#endif
+#if NEED_PCI == 1
+struct pci_filter;
+struct pci_dev *pci_dev_find_filter(struct pci_filter filter);
+struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t devclass);
+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
+int rget_io_perms(void);
+#if CONFIG_INTERNAL == 1
+extern int is_laptop;
+extern int laptop_ok;
+extern int force_boardenable;
+extern int force_boardmismatch;
+void probe_superio(void);
+int register_superio(struct superio s);
+extern enum chipbustype internal_buses_supported;
+int internal_init(void);
+#endif
+
+/* hwaccess.c */
+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 mmio_readn(void *addr, uint8_t *buf, size_t len);
+void mmio_le_writeb(uint8_t val, void *addr);
+void mmio_le_writew(uint16_t val, void *addr);
+void mmio_le_writel(uint32_t val, void *addr);
+uint8_t mmio_le_readb(void *addr);
+uint16_t mmio_le_readw(void *addr);
+uint32_t mmio_le_readl(void *addr);
+#define pci_mmio_writeb mmio_le_writeb
+#define pci_mmio_writew mmio_le_writew
+#define pci_mmio_writel mmio_le_writel
+#define pci_mmio_readb mmio_le_readb
+#define pci_mmio_readw mmio_le_readw
+#define pci_mmio_readl mmio_le_readl
+void rmmio_writeb(uint8_t val, void *addr);
+void rmmio_writew(uint16_t val, void *addr);
+void rmmio_writel(uint32_t val, void *addr);
+void rmmio_le_writeb(uint8_t val, void *addr);
+void rmmio_le_writew(uint16_t val, void *addr);
+void rmmio_le_writel(uint32_t val, void *addr);
+#define pci_rmmio_writeb rmmio_le_writeb
+#define pci_rmmio_writew rmmio_le_writew
+#define pci_rmmio_writel rmmio_le_writel
+void rmmio_valb(void *addr);
+void rmmio_valw(void *addr);
+void rmmio_vall(void *addr);
+
+/* dummyflasher.c */
+#if CONFIG_DUMMY == 1
+int dummy_init(void);
+void *dummy_map(const char *descr, unsigned long phys_addr, size_t len);
+void dummy_unmap(void *virt_addr, size_t len);
+#endif
+
+/* nic3com.c */
+#if CONFIG_NIC3COM == 1
+int nic3com_init(void);
+extern const struct pcidev_status nics_3com[];
+#endif
+
+/* gfxnvidia.c */
+#if CONFIG_GFXNVIDIA == 1
+int gfxnvidia_init(void);
+extern const struct pcidev_status gfx_nvidia[];
+#endif
+
+/* drkaiser.c */
+#if CONFIG_DRKAISER == 1
+int drkaiser_init(void);
+extern const struct pcidev_status drkaiser_pcidev[];
+#endif
+
+/* nicrealtek.c */
+#if CONFIG_NICREALTEK == 1
+int nicrealtek_init(void);
+extern const struct pcidev_status nics_realtek[];
+#endif
+
+/* nicnatsemi.c */
+#if CONFIG_NICNATSEMI == 1
+int nicnatsemi_init(void);
+extern const struct pcidev_status nics_natsemi[];
+#endif
+
+/* nicintel.c */
+#if CONFIG_NICINTEL == 1
+int nicintel_init(void);
+extern const struct pcidev_status nics_intel[];
+#endif
+
+/* nicintel_spi.c */
+#if CONFIG_NICINTEL_SPI == 1
+int nicintel_spi_init(void);
+extern const struct pcidev_status nics_intel_spi[];
+#endif
+
+/* ogp_spi.c */
+#if CONFIG_OGP_SPI == 1
+int ogp_spi_init(void);
+extern const struct pcidev_status ogp_spi[];
+#endif
+
+/* satamv.c */
+#if CONFIG_SATAMV == 1
+int satamv_init(void);
+extern const struct pcidev_status satas_mv[];
+#endif
+
+/* satasii.c */
+#if CONFIG_SATASII == 1
+int satasii_init(void);
+extern const struct pcidev_status satas_sii[];
+#endif
+
+/* atahpt.c */
+#if CONFIG_ATAHPT == 1
+int atahpt_init(void);
+extern const struct pcidev_status ata_hpt[];
+#endif
+
+/* ft2232_spi.c */
+#if CONFIG_FT2232_SPI == 1
+struct usbdev_status {
+       uint16_t vendor_id;
+       uint16_t device_id;
+       const enum test_state status;
+       const char *vendor_name;
+       const char *device_name;
+};
+int ft2232_spi_init(void);
+extern const struct usbdev_status devs_ft2232spi[];
+void print_supported_usbdevs(const struct usbdev_status *devs);
+#endif
+
+/* rayer_spi.c */
+#if CONFIG_RAYER_SPI == 1
+int rayer_spi_init(void);
+#endif
+
+/* pony_spi.c */
+#if CONFIG_PONY_SPI == 1
+int pony_spi_init(void);
+#endif
+
+/* bitbang_spi.c */
+int bitbang_spi_init(const struct bitbang_spi_master *master);
+
+/* buspirate_spi.c */
+#if CONFIG_BUSPIRATE_SPI == 1
+int buspirate_spi_init(void);
+#endif
+
+/* linux_spi.c */
+#if CONFIG_LINUX_SPI == 1
+int linux_spi_init(void);
+#endif
+
+/* dediprog.c */
+#if CONFIG_DEDIPROG == 1
+int dediprog_init(void);
+#endif
+
+/* flashrom.c */
+struct decode_sizes {
+       uint32_t parallel;
+       uint32_t lpc;
+       uint32_t fwh;
+       uint32_t spi;
+};
+// FIXME: These need to be local, not global
+extern struct decode_sizes max_rom_decode;
+extern int programmer_may_write;
+extern unsigned long flashbase;
+void check_chip_supported(const struct flashctx *flash);
+int check_max_decode(enum chipbustype buses, uint32_t size);
+char *extract_programmer_param(const char *param_name);
+
+/* layout.c */
+int show_id(uint8_t *bios, int size, int force);
+
+/* spi.c */
+enum spi_controller {
+       SPI_CONTROLLER_NONE,
+#if CONFIG_INTERNAL == 1
+#if defined(__i386__) || defined(__x86_64__)
+       SPI_CONTROLLER_ICH7,
+       SPI_CONTROLLER_ICH9,
+       SPI_CONTROLLER_IT85XX,
+       SPI_CONTROLLER_IT87XX,
+       SPI_CONTROLLER_SB600,
+       SPI_CONTROLLER_VIA,
+       SPI_CONTROLLER_WBSIO,
+#endif
+#endif
+#if CONFIG_FT2232_SPI == 1
+       SPI_CONTROLLER_FT2232,
+#endif
+#if CONFIG_DUMMY == 1
+       SPI_CONTROLLER_DUMMY,
+#endif
+#if CONFIG_BUSPIRATE_SPI == 1
+       SPI_CONTROLLER_BUSPIRATE,
+#endif
+#if CONFIG_DEDIPROG == 1
+       SPI_CONTROLLER_DEDIPROG,
+#endif
+#if CONFIG_OGP_SPI == 1 || CONFIG_NICINTEL_SPI == 1 || CONFIG_RAYER_SPI == 1 || CONFIG_PONY_SPI == 1 || (CONFIG_INTERNAL == 1 && (defined(__i386__) || defined(__x86_64__)))
+       SPI_CONTROLLER_BITBANG,
+#endif
+#if CONFIG_LINUX_SPI == 1
+       SPI_CONTROLLER_LINUX,
+#endif
+#if CONFIG_SERPROG == 1
+       SPI_CONTROLLER_SERPROG,
+#endif
+};
+
+#define MAX_DATA_UNSPECIFIED 0
+#define MAX_DATA_READ_UNLIMITED 64 * 1024
+#define MAX_DATA_WRITE_UNLIMITED 256
+struct spi_programmer {
+       enum spi_controller type;
+       unsigned int max_data_read;
+       unsigned int max_data_write;
+       int (*command)(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+                  const unsigned char *writearr, unsigned char *readarr);
+       int (*multicommand)(struct flashctx *flash, struct spi_command *cmds);
+
+       /* Optimized functions for this programmer */
+       int (*read)(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       int (*write_256)(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       int (*write_aai)(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       const void *data;
+};
+
+int default_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+                            const unsigned char *writearr, unsigned char *readarr);
+int default_spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds);
+int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int default_spi_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int register_spi_programmer(const struct spi_programmer *programmer);
+
+/* The following enum is needed by ich_descriptor_tool and ich* code. */
+enum ich_chipset {
+       CHIPSET_ICH_UNKNOWN,
+       CHIPSET_ICH7 = 7,
+       CHIPSET_ICH8,
+       CHIPSET_ICH9,
+       CHIPSET_ICH10,
+       CHIPSET_5_SERIES_IBEX_PEAK,
+       CHIPSET_6_SERIES_COUGAR_POINT,
+       CHIPSET_7_SERIES_PANTHER_POINT,
+       CHIPSET_8_SERIES_LYNX_POINT
+};
+
+/* ichspi.c */
+#if CONFIG_INTERNAL == 1
+extern uint32_t ichspi_bbar;
+int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
+                enum ich_chipset ich_generation);
+int via_init_spi(struct pci_dev *dev);
+
+/* it85spi.c */
+int it85xx_spi_init(struct superio s);
+
+/* it87spi.c */
+void enter_conf_mode_ite(uint16_t port);
+void exit_conf_mode_ite(uint16_t port);
+void probe_superio_ite(void);
+int init_superio_ite(void);
+
+/* mcp6x_spi.c */
+int mcp6x_spi_init(int want_spi);
+
+/* sb600spi.c */
+int sb600_probe_spi(struct pci_dev *dev);
+
+/* wbsio_spi.c */
+int wbsio_check_for_spi(void);
+#endif
+
+/* opaque.c */
+struct opaque_programmer {
+       int max_data_read;
+       int max_data_write;
+       /* Specific functions for this programmer */
+       int (*probe) (struct flashctx *flash);
+       int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       int (*write) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+       int (*erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+       const void *data;
+};
+int register_opaque_programmer(const struct opaque_programmer *pgm);
+
+/* 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 noop_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
+void fallback_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
+void fallback_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr);
+void fallback_chip_writen(const struct flashctx *flash, uint8_t *buf, chipaddr addr, size_t len);
+uint16_t fallback_chip_readw(const struct flashctx *flash, const chipaddr addr);
+uint32_t fallback_chip_readl(const struct flashctx *flash, const chipaddr addr);
+void fallback_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
+struct par_programmer {
+       void (*chip_writeb) (const struct flashctx *flash, uint8_t val, chipaddr addr);
+       void (*chip_writew) (const struct flashctx *flash, uint16_t val, chipaddr addr);
+       void (*chip_writel) (const struct flashctx *flash, uint32_t val, chipaddr addr);
+       void (*chip_writen) (const struct flashctx *flash, uint8_t *buf, chipaddr addr, size_t len);
+       uint8_t (*chip_readb) (const struct flashctx *flash, const chipaddr addr);
+       uint16_t (*chip_readw) (const struct flashctx *flash, const chipaddr addr);
+       uint32_t (*chip_readl) (const struct flashctx *flash, const chipaddr addr);
+       void (*chip_readn) (const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
+       const void *data;
+};
+int register_par_programmer(const struct par_programmer *pgm, const enum chipbustype buses);
+struct registered_programmer {
+       enum chipbustype buses_supported;
+       union {
+               struct par_programmer par;
+               struct spi_programmer spi;
+               struct opaque_programmer opaque;
+       };
+};
+extern struct registered_programmer registered_programmers[];
+extern int registered_programmer_count;
+int register_programmer(struct registered_programmer *pgm);
+
+/* serprog.c */
+#if CONFIG_SERPROG == 1
+int serprog_init(void);
+void serprog_delay(int usecs);
+#endif
+
+/* 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;
+/* expose serialport_shutdown as it's currently used by buspirate */
+int serialport_shutdown(void *data);
+int serialport_write(unsigned char *buf, unsigned int writecnt);
+int serialport_read(unsigned char *buf, unsigned int readcnt);
+
+/* Serial port/pin mapping:
+
+  1    CD      <-
+  2    RXD     <-
+  3    TXD     ->
+  4    DTR     ->
+  5    GND     --
+  6    DSR     <-
+  7    RTS     ->
+  8    CTS     <-
+  9    RI      <-
+*/
+enum SP_PIN {
+       PIN_CD = 1,
+       PIN_RXD,
+       PIN_TXD,
+       PIN_DTR,
+       PIN_GND,
+       PIN_DSR,
+       PIN_RTS,
+       PIN_CTS,
+       PIN_RI,
+};
+
+void sp_set_pin(enum SP_PIN pin, int val);
+int sp_get_pin(enum SP_PIN pin);
+
+#endif                         /* !__PROGRAMMER_H__ */
diff --git a/rayer_spi.c b/rayer_spi.c
new file mode 100644 (file)
index 0000000..8e48e6e
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * 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; 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
+ */
+
+/* Driver for the SPIPGM hardware by "RayeR" Martin Rehak.
+ * See http://rayer.ic.cz/elektro/spipgm.htm for schematics and instructions.
+ */
+
+/* This driver uses non-portable direct I/O port accesses which won't work on
+ * any non-x86 platform, and even on x86 there is a high chance there will be
+ * collisions with any loaded parallel port drivers.
+ * The big advantage of direct port I/O is OS independence and speed because
+ * most OS parport drivers will perform many unnecessary accesses although
+ * this driver just treats the parallel port as a GPIO set.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+enum rayer_type {
+       TYPE_RAYER,
+       TYPE_XILINX_DLC5,
+};
+
+/* We have two sets of pins, out and in. The numbers for both sets are
+ * independent and are bitshift values, not real pin numbers.
+ * Default settings are for the RayeR hardware.
+ */
+/* Pins for master->slave direction */
+static int rayer_cs_bit = 5;
+static int rayer_sck_bit = 6;
+static int rayer_mosi_bit = 7;
+/* Pins for slave->master direction */
+static int rayer_miso_bit = 6;
+
+static uint16_t lpt_iobase;
+
+/* Cached value of last byte sent. */
+static uint8_t lpt_outbyte;
+
+static void rayer_bitbang_set_cs(int val)
+{
+       lpt_outbyte &= ~(1 << rayer_cs_bit);
+       lpt_outbyte |= (val << rayer_cs_bit);
+       OUTB(lpt_outbyte, lpt_iobase);
+}
+
+static void rayer_bitbang_set_sck(int val)
+{
+       lpt_outbyte &= ~(1 << rayer_sck_bit);
+       lpt_outbyte |= (val << rayer_sck_bit);
+       OUTB(lpt_outbyte, lpt_iobase);
+}
+
+static void rayer_bitbang_set_mosi(int val)
+{
+       lpt_outbyte &= ~(1 << rayer_mosi_bit);
+       lpt_outbyte |= (val << rayer_mosi_bit);
+       OUTB(lpt_outbyte, lpt_iobase);
+}
+
+static int rayer_bitbang_get_miso(void)
+{
+       uint8_t tmp;
+
+       tmp = INB(lpt_iobase + 1);
+       tmp = (tmp >> rayer_miso_bit) & 0x1;
+       return tmp;
+}
+
+static const struct bitbang_spi_master bitbang_spi_master_rayer = {
+       .type = BITBANG_SPI_MASTER_RAYER,
+       .set_cs = rayer_bitbang_set_cs,
+       .set_sck = rayer_bitbang_set_sck,
+       .set_mosi = rayer_bitbang_set_mosi,
+       .get_miso = rayer_bitbang_get_miso,
+       .half_period = 0,
+};
+
+int rayer_spi_init(void)
+{
+       char *arg = NULL;
+       enum rayer_type rayer_type = TYPE_RAYER;
+
+       /* Non-default port requested? */
+       arg = extract_programmer_param("iobase");
+       if (arg) {
+               char *endptr = NULL;
+               unsigned long tmp;
+               tmp = strtoul(arg, &endptr, 0);
+               /* Port 0, port >0x10000, unaligned ports and garbage strings
+                * are rejected.
+                */
+               if (!tmp || (tmp >= 0x10000) || (tmp & 0x3) ||
+                   (*endptr != '\0')) {
+                       /* Using ports below 0x100 is a really bad idea, and
+                        * should only be done if no port between 0x100 and
+                        * 0xfffc works due to routing issues.
+                        */
+                       msg_perr("Error: iobase= specified, but the I/O base "
+                                "given was invalid.\nIt must be a multiple of "
+                                "0x4 and lie between 0x100 and 0xfffc.\n");
+                       free(arg);
+                       return 1;
+               } else {
+                       lpt_iobase = (uint16_t)tmp;
+                       msg_pinfo("Non-default I/O base requested. This will "
+                                 "not change the hardware settings.\n");
+               }
+       } else {
+               /* Pick a default value for the I/O base. */
+               lpt_iobase = 0x378;
+       }
+       free(arg);
+       
+       msg_pdbg("Using address 0x%x as I/O base for parallel port access.\n",
+                lpt_iobase);
+
+       arg = extract_programmer_param("type");
+       if (arg) {
+               if (!strcasecmp(arg, "rayer")) {
+                       rayer_type = TYPE_RAYER;
+               } else if (!strcasecmp(arg, "xilinx")) {
+                       rayer_type = TYPE_XILINX_DLC5;
+               } else {
+                       msg_perr("Error: Invalid device type specified.\n");
+                       free(arg);
+                       return 1;
+               }
+       }
+       free(arg);
+       switch (rayer_type) {
+       case TYPE_RAYER:
+               msg_pdbg("Using RayeR SPIPGM pinout.\n");
+               /* Bits for master->slave direction */
+               rayer_cs_bit = 5;
+               rayer_sck_bit = 6;
+               rayer_mosi_bit = 7;
+               /* Bits for slave->master direction */
+               rayer_miso_bit = 6;
+               break;
+       case TYPE_XILINX_DLC5:
+               msg_pdbg("Using Xilinx Parallel Cable III (DLC 5) pinout.\n");
+               /* Bits for master->slave direction */
+               rayer_cs_bit = 2;
+               rayer_sck_bit = 1;
+               rayer_mosi_bit = 0;
+               /* Bits for slave->master direction */
+               rayer_miso_bit = 4;
+       }
+
+       if (rget_io_perms())
+               return 1;
+
+       /* Get the initial value before writing to any line. */
+       lpt_outbyte = INB(lpt_iobase);
+
+       if (bitbang_spi_init(&bitbang_spi_master_rayer))
+               return 1;
+
+       return 0;
+}
+
+#else
+#error PCI port I/O access is not supported on this architecture yet.
+#endif
diff --git a/satamv.c b/satamv.c
new file mode 100644 (file)
index 0000000..afcabaf
--- /dev/null
+++ b/satamv.c
@@ -0,0 +1,205 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010,2011 Carl-Daniel Hailfinger
+ * Written by Carl-Daniel Hailfinger for Angelbird Ltd.
+ *
+ * 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
+ */
+
+/* Datasheets are not public (yet?) */
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+uint8_t *mv_bar;
+uint16_t mv_iobar;
+
+const struct pcidev_status satas_mv[] = {
+       /* 88SX6041 and 88SX6042 are the same according to the datasheet. */
+       {0x11ab, 0x7042, OK, "Marvell", "88SX7042 PCI-e 4-port SATA-II"},
+
+       {},
+};
+
+#define NVRAM_PARAM                    0x1045c
+#define FLASH_PARAM                    0x1046c
+#define EXPANSION_ROM_BAR_CONTROL      0x00d2c
+#define PCI_BAR2_CONTROL               0x00c08
+#define GPIO_PORT_CONTROL              0x104f0
+
+static void satamv_chip_writeb(const struct flashctx *flash, uint8_t val,
+                              chipaddr addr);
+static uint8_t satamv_chip_readb(const struct flashctx *flash,
+                                const chipaddr addr);
+static const struct par_programmer par_programmer_satamv = {
+               .chip_readb             = satamv_chip_readb,
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = fallback_chip_readn,
+               .chip_writeb            = satamv_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+static int satamv_shutdown(void *data)
+{
+       physunmap(mv_bar, 0x20000);
+       pci_cleanup(pacc);
+       return 0;
+}
+
+/*
+ * Random notes:
+ * FCE#                Flash Chip Enable
+ * FWE#                Flash Write Enable
+ * FOE#                Flash Output Enable
+ * FALE[1:0]   Flash Address Latch Enable
+ * FAD[7:0]    Flash Multiplexed Address/Data Bus
+ * FA[2:0]     Flash Address Low
+ *
+ * GPIO[15,2]  GPIO Port Mode
+ * GPIO[4:3]   Flash Size
+ *
+ * 0xd2c       Expansion ROM BAR Control
+ * 0xc08       PCI BAR2 (Flash/NVRAM) Control
+ * 0x1046c     Flash Parameters
+ */
+int satamv_init(void)
+{
+       uintptr_t addr;
+       uint32_t tmp;
+
+       if (rget_io_perms())
+               return 1;
+
+       /* BAR0 has all internal registers memory mapped. */
+       /* No need to check for errors, pcidev_init() will not return in case
+        * of errors.
+        */
+       addr = pcidev_init(PCI_BASE_ADDRESS_0, satas_mv);
+
+       mv_bar = physmap("Marvell 88SX7042 registers", addr, 0x20000);
+       if (mv_bar == ERROR_PTR)
+               goto error_out;
+
+       if (register_shutdown(satamv_shutdown, NULL))
+               return 1;
+
+       tmp = pci_mmio_readl(mv_bar + FLASH_PARAM);
+       msg_pspew("Flash Parameters:\n");
+       msg_pspew("TurnOff=0x%01x\n", (tmp >> 0) & 0x7);
+       msg_pspew("Acc2First=0x%01x\n", (tmp >> 3) & 0xf);
+       msg_pspew("Acc2Next=0x%01x\n", (tmp >> 7) & 0xf);
+       msg_pspew("ALE2Wr=0x%01x\n", (tmp >> 11) & 0x7);
+       msg_pspew("WrLow=0x%01x\n", (tmp >> 14) & 0x7);
+       msg_pspew("WrHigh=0x%01x\n", (tmp >> 17) & 0x7);
+       msg_pspew("Reserved[21:20]=0x%01x\n", (tmp >> 20) & 0x3);
+       msg_pspew("TurnOffExt=0x%01x\n", (tmp >> 22) & 0x1);
+       msg_pspew("Acc2FirstExt=0x%01x\n", (tmp >> 23) & 0x1);
+       msg_pspew("Acc2NextExt=0x%01x\n", (tmp >> 24) & 0x1);
+       msg_pspew("ALE2WrExt=0x%01x\n", (tmp >> 25) & 0x1);
+       msg_pspew("WrLowExt=0x%01x\n", (tmp >> 26) & 0x1);
+       msg_pspew("WrHighExt=0x%01x\n", (tmp >> 27) & 0x1);
+       msg_pspew("Reserved[31:28]=0x%01x\n", (tmp >> 28) & 0xf);
+
+       tmp = pci_mmio_readl(mv_bar + EXPANSION_ROM_BAR_CONTROL);
+       msg_pspew("Expansion ROM BAR Control:\n");
+       msg_pspew("ExpROMSz=0x%01x\n", (tmp >> 19) & 0x7);
+
+       /* Enable BAR2 mapping to flash */
+       tmp = pci_mmio_readl(mv_bar + PCI_BAR2_CONTROL);
+       msg_pspew("PCI BAR2 (Flash/NVRAM) Control:\n");
+       msg_pspew("Bar2En=0x%01x\n", (tmp >> 0) & 0x1);
+       msg_pspew("BAR2TransAttr=0x%01x\n", (tmp >> 1) & 0x1f);
+       msg_pspew("BAR2Sz=0x%01x\n", (tmp >> 19) & 0x7);
+       tmp &= 0xffffffc0;
+       tmp |= 0x0000001f;
+       pci_rmmio_writel(tmp, mv_bar + PCI_BAR2_CONTROL);
+
+       /* Enable flash: GPIO Port Control Register 0x104f0 */
+       tmp = pci_mmio_readl(mv_bar + GPIO_PORT_CONTROL);
+       msg_pspew("GPIOPortMode=0x%01x\n", (tmp >> 0) & 0x3);
+       if (((tmp >> 0) & 0x3) != 0x2)
+               msg_pinfo("Warning! Either the straps are incorrect or you "
+                         "have no flash or someone overwrote the strap "
+                         "values!\n");
+       tmp &= 0xfffffffc;
+       tmp |= 0x2;
+       pci_rmmio_writel(tmp, mv_bar + GPIO_PORT_CONTROL);
+
+       /* Get I/O BAR location. */
+       tmp = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) &
+             PCI_BASE_ADDRESS_IO_MASK;
+       /* Truncate to reachable range.
+        * FIXME: Check if the I/O BAR is actually reachable.
+        * This is an arch specific check.
+        */
+       mv_iobar = tmp & 0xffff;
+       msg_pspew("Activating I/O BAR at 0x%04x\n", mv_iobar);
+
+       /* 512 kByte with two 8-bit latches, and
+        * 4 MByte with additional 3-bit latch. */
+       max_rom_decode.parallel = 4 * 1024 * 1024;
+       register_par_programmer(&par_programmer_satamv, BUS_PARALLEL);
+
+       return 0;
+
+error_out:
+       pci_cleanup(pacc);
+       return 1;
+}
+
+/* BAR2 (MEM) can map NVRAM and flash. We set it to flash in the init function.
+ * If BAR2 is disabled, it still can be accessed indirectly via BAR1 (I/O).
+ * This code only supports indirect accesses for now.
+ */
+
+/* Indirect access to via the I/O BAR1. */
+static void satamv_indirect_chip_writeb(uint8_t val, chipaddr addr)
+{
+       /* 0x80000000 selects BAR2 for remapping. */
+       OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, mv_iobar);
+       OUTB(val, mv_iobar + 0x80 + (addr & 0x3));
+}
+
+/* Indirect access to via the I/O BAR1. */
+static uint8_t satamv_indirect_chip_readb(const chipaddr addr)
+{
+       /* 0x80000000 selects BAR2 for remapping. */
+       OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, mv_iobar);
+       return INB(mv_iobar + 0x80 + (addr & 0x3));
+}
+
+/* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
+static void satamv_chip_writeb(const struct flashctx *flash, uint8_t val,
+                              chipaddr addr)
+{
+       satamv_indirect_chip_writeb(val, addr);
+}
+
+/* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
+static uint8_t satamv_chip_readb(const struct flashctx *flash,
+                                const chipaddr addr)
+{
+       return satamv_indirect_chip_readb(addr);
+}
+
+#else
+#error PCI port I/O access is not supported on this architecture yet.
+#endif
diff --git a/satasii.c b/satasii.c
new file mode 100644 (file)
index 0000000..0bea942
--- /dev/null
+++ b/satasii.c
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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
+ */
+
+/* Datasheets can be found on http://www.siliconimage.com. Great thanks! */
+
+#include <stdlib.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_SII      0x1095
+
+#define SATASII_MEMMAP_SIZE    0x100
+
+uint8_t *sii_bar;
+static uint16_t id;
+
+const struct pcidev_status satas_sii[] = {
+       {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, OK, "Silicon Image", "SiI 3124 PCI-X SATA Ctrl"},
+       {0x1095, 0x3132, OK, "Silicon Image", "SiI 3132 SATA Raid II Ctrl"},
+       {0x1095, 0x3512, OK, "Silicon Image", "SiI 3512 [SATALink/SATARaid] SATA Ctrl"},
+
+       {},
+};
+
+static void satasii_chip_writeb(const struct flashctx *flash, uint8_t val,
+                               chipaddr addr);
+static uint8_t satasii_chip_readb(const struct flashctx *flash,
+                                 const chipaddr addr);
+static const struct par_programmer par_programmer_satasii = {
+               .chip_readb             = satasii_chip_readb,
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = fallback_chip_readn,
+               .chip_writeb            = satasii_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+static int satasii_shutdown(void *data)
+{
+       physunmap(sii_bar, SATASII_MEMMAP_SIZE);
+       pci_cleanup(pacc);
+       return 0;
+}
+
+int satasii_init(void)
+{
+       uint32_t addr;
+       uint16_t reg_offset;
+
+       if (rget_io_perms())
+               return 1;
+
+       pcidev_init(PCI_BASE_ADDRESS_0, satas_sii);
+
+       id = pcidev_dev->device_id;
+
+       if ((id == 0x3132) || (id == 0x3124)) {
+               addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_0) & ~0x07;
+               reg_offset = 0x70;
+       } else {
+               addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_5) & ~0x07;
+               reg_offset = 0x50;
+       }
+
+       sii_bar = physmap("SATA SIL registers", addr, SATASII_MEMMAP_SIZE) +
+                 reg_offset;
+
+       /* Check if ROM cycle are OK. */
+       if ((id != 0x0680) && (!(pci_mmio_readl(sii_bar) & (1 << 26))))
+               msg_pinfo("Warning: Flash seems unconnected.\n");
+
+       if (register_shutdown(satasii_shutdown, NULL))
+               return 1;
+
+       register_par_programmer(&par_programmer_satasii, BUS_PARALLEL);
+
+       return 0;
+}
+
+static void satasii_chip_writeb(const struct flashctx *flash, uint8_t val,
+                               chipaddr addr)
+{
+       uint32_t ctrl_reg, data_reg;
+
+       while ((ctrl_reg = pci_mmio_readl(sii_bar)) & (1 << 25)) ;
+
+       /* Mask out unused/reserved bits, set writes and start transaction. */
+       ctrl_reg &= 0xfcf80000;
+       ctrl_reg |= (1 << 25) | (0 << 24) | ((uint32_t) addr & 0x7ffff);
+
+       data_reg = (pci_mmio_readl((sii_bar + 4)) & ~0xff) | val;
+       pci_mmio_writel(data_reg, (sii_bar + 4));
+       pci_mmio_writel(ctrl_reg, sii_bar);
+
+       while (pci_mmio_readl(sii_bar) & (1 << 25)) ;
+}
+
+static uint8_t satasii_chip_readb(const struct flashctx *flash,
+                                 const chipaddr addr)
+{
+       uint32_t ctrl_reg;
+
+       while ((ctrl_reg = pci_mmio_readl(sii_bar)) & (1 << 25)) ;
+
+       /* Mask out unused/reserved bits, set reads and start transaction. */
+       ctrl_reg &= 0xfcf80000;
+       ctrl_reg |= (1 << 25) | (1 << 24) | ((uint32_t) addr & 0x7ffff);
+
+       pci_mmio_writel(ctrl_reg, sii_bar);
+
+       while (pci_mmio_readl(sii_bar) & (1 << 25)) ;
+
+       return (pci_mmio_readl(sii_bar + 4)) & 0xff;
+}
diff --git a/sb600spi.c b/sb600spi.c
new file mode 100644 (file)
index 0000000..fe60aa9
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Wang Qingpei <Qingpei.Wang@amd.com>
+ * Copyright (C) 2008 Joe Bao <Zheng.Bao@amd.com>
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ * 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
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+#include "spi.h"
+
+/* This struct is unused, but helps visualize the SB600 SPI BAR layout.
+ *struct sb600_spi_controller {
+ *     unsigned int spi_cntrl0;        / * 00h * /
+ *     unsigned int restrictedcmd1;    / * 04h * /
+ *     unsigned int restrictedcmd2;    / * 08h * /
+ *     unsigned int spi_cntrl1;        / * 0ch * /
+ *     unsigned int spi_cmdvalue0;     / * 10h * /
+ *     unsigned int spi_cmdvalue1;     / * 14h * /
+ *     unsigned int spi_cmdvalue2;     / * 18h * /
+ *     unsigned int spi_fakeid;        / * 1Ch * /
+ *};
+ */
+
+static uint8_t *sb600_spibar = NULL;
+
+static void reset_internal_fifo_pointer(void)
+{
+       mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
+
+       /* FIXME: This loop makes no sense at all. */
+       while (mmio_readb(sb600_spibar + 0xD) & 0x7)
+               msg_pspew("reset\n");
+}
+
+static int compare_internal_fifo_pointer(uint8_t want)
+{
+       uint8_t tmp;
+
+       tmp = mmio_readb(sb600_spibar + 0xd) & 0x07;
+       want &= 0x7;
+       if (want != tmp) {
+               msg_perr("SB600 FIFO pointer corruption! Pointer is %d, wanted "
+                        "%d\n", tmp, want);
+               msg_perr("Something else is accessing the flash chip and "
+                        "causes random corruption.\nPlease stop all "
+                        "applications and drivers and IPMI which access the "
+                        "flash chip.\n");
+               return 1;
+       } else {
+               msg_pspew("SB600 FIFO pointer is %d, wanted %d\n", tmp, want);
+               return 0;
+       }
+}
+
+static int reset_compare_internal_fifo_pointer(uint8_t want)
+{
+       int ret;
+
+       ret = compare_internal_fifo_pointer(want);
+       reset_internal_fifo_pointer();
+       return ret;
+}
+
+static void execute_command(void)
+{
+       mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
+
+       while (mmio_readb(sb600_spibar + 2) & 1)
+               ;
+}
+
+static int sb600_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                                 unsigned int readcnt,
+                                 const unsigned char *writearr,
+                                 unsigned char *readarr)
+{
+       int count;
+       /* First byte is cmd which can not being sent through FIFO. */
+       unsigned char cmd = *writearr++;
+       unsigned int readoffby1;
+       unsigned char readwrite;
+
+       writecnt--;
+
+       msg_pspew("%s, cmd=%x, writecnt=%x, readcnt=%x\n",
+                 __func__, cmd, writecnt, readcnt);
+
+       if (readcnt > 8) {
+               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) {
+               msg_pinfo("%s, SB600 SPI controller can not send %d bytes, "
+                      "it is limited to 8 bytes\n", __func__, writecnt);
+               return SPI_INVALID_LENGTH;
+       }
+
+       /* This is a workaround for a bug in SB600 and SB700. If we only send
+        * an opcode and no additional data/address, the SPI controller will
+        * read one byte too few from the chip. Basically, the last byte of
+        * the chip response is discarded and will not end up in the FIFO.
+        * It is unclear if the CS# line is set high too early as well.
+        */
+       readoffby1 = (writecnt) ? 0 : 1;
+       readwrite = (readcnt + readoffby1) << 4 | (writecnt);
+       mmio_writeb(readwrite, sb600_spibar + 1);
+       mmio_writeb(cmd, sb600_spibar + 0);
+
+       /* Before we use the FIFO, reset it first. */
+       reset_internal_fifo_pointer();
+
+       /* Send the write byte to FIFO. */
+       msg_pspew("Writing: ");
+       for (count = 0; count < writecnt; count++, writearr++) {
+               msg_pspew("[%02x]", *writearr);
+               mmio_writeb(*writearr, sb600_spibar + 0xC);
+       }
+       msg_pspew("\n");
+
+       /*
+        * We should send the data by sequence, which means we need to reset
+        * the FIFO pointer to the first byte we want to send.
+        */
+       if (reset_compare_internal_fifo_pointer(writecnt))
+               return SPI_PROGRAMMER_ERROR;
+
+       msg_pspew("Executing: \n");
+       execute_command();
+
+       /*
+        * After the command executed, we should find out the index of the
+        * received byte. Here we just reset the FIFO pointer and skip the
+        * writecnt.
+        * It would be possible to increase the FIFO pointer by one instead
+        * of reading and discarding one byte from the FIFO.
+        * The FIFO is implemented on top of an 8 byte ring buffer and the
+        * buffer is never cleared. For every byte that is shifted out after
+        * the opcode, the FIFO already stores the response from the chip.
+        * Usually, the chip will respond with 0x00 or 0xff.
+        */
+       if (reset_compare_internal_fifo_pointer(writecnt + readcnt))
+               return SPI_PROGRAMMER_ERROR;
+
+       /* Skip the bytes we sent. */
+       msg_pspew("Skipping: ");
+       for (count = 0; count < writecnt; count++) {
+               cmd = mmio_readb(sb600_spibar + 0xC);
+               msg_pspew("[%02x]", cmd);
+       }
+       msg_pspew("\n");
+       if (compare_internal_fifo_pointer(writecnt))
+               return SPI_PROGRAMMER_ERROR;
+
+       msg_pspew("Reading: ");
+       for (count = 0; count < readcnt; count++, readarr++) {
+               *readarr = mmio_readb(sb600_spibar + 0xC);
+               msg_pspew("[%02x]", *readarr);
+       }
+       msg_pspew("\n");
+       if (reset_compare_internal_fifo_pointer(readcnt + writecnt))
+               return SPI_PROGRAMMER_ERROR;
+
+       if (mmio_readb(sb600_spibar + 1) != readwrite) {
+               msg_perr("Unexpected change in SB600 read/write count!\n");
+               msg_perr("Something else is accessing the flash chip and "
+                        "causes random corruption.\nPlease stop all "
+                        "applications and drivers and IPMI which access the "
+                        "flash chip.\n");
+               return SPI_PROGRAMMER_ERROR;
+       }
+
+       return 0;
+}
+
+static const struct spi_programmer spi_programmer_sb600 = {
+       .type = SPI_CONTROLLER_SB600,
+       .max_data_read = 8,
+       .max_data_write = 5,
+       .command = sb600_spi_send_command,
+       .multicommand = default_spi_send_multicommand,
+       .read = default_spi_read,
+       .write_256 = default_spi_write_256,
+       .write_aai = default_spi_write_aai,
+};
+
+int sb600_probe_spi(struct pci_dev *dev)
+{
+       struct pci_dev *smbus_dev;
+       uint32_t tmp;
+       uint8_t reg;
+       static const char *const speed_names[4] = {
+               "Reserved", "33", "22", "16.5"
+       };
+
+       /* Read SPI_BaseAddr */
+       tmp = pci_read_long(dev, 0xa0);
+       tmp &= 0xffffffe0;      /* remove bits 4-0 (reserved) */
+       msg_pdbg("SPI base address is at 0x%x\n", tmp);
+
+       /* If the BAR has address 0, it is unlikely SPI is used. */
+       if (!tmp)
+               return 0;
+
+       /* Physical memory has to be mapped at page (4k) boundaries. */
+       sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000,
+                              0x1000);
+       /* The low bits of the SPI base address are used as offset into
+        * the mapped page.
+        */
+       sb600_spibar += tmp & 0xfff;
+
+       tmp = pci_read_long(dev, 0xa0);
+       msg_pdbg("AltSpiCSEnable=%i, SpiRomEnable=%i, "
+                    "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1,
+                    (tmp & 0x4) >> 2);
+       tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2;
+       msg_pdbg("PrefetchEnSPIFromIMC=%i, ", tmp);
+
+       tmp = pci_read_byte(dev, 0xbb);
+       /* FIXME: Set bit 3,6,7 if not already set.
+        * Set bit 5, otherwise SPI accesses are pointless in LPC mode.
+        * See doc 42413 AMD SB700/710/750 RPR.
+        */
+       msg_pdbg("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n",
+                    tmp & 0x1, (tmp & 0x20) >> 5);
+       tmp = mmio_readl(sb600_spibar);
+       /* FIXME: If SpiAccessMacRomEn or SpiHostAccessRomEn are zero on
+        * SB700 or later, reads and writes will be corrupted. Abort in this
+        * case. Make sure to avoid this check on SB600.
+        */
+       msg_pdbg("SpiArbEnable=%i, SpiAccessMacRomEn=%i, "
+                    "SpiHostAccessRomEn=%i, ArbWaitCount=%i, "
+                    "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n",
+                    (tmp >> 19) & 0x1, (tmp >> 22) & 0x1,
+                    (tmp >> 23) & 0x1, (tmp >> 24) & 0x7,
+                    (tmp >> 27) & 0x1, (tmp >> 28) & 0x1);
+       tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3;
+       msg_pdbg("NormSpeed is %s MHz\n", speed_names[tmp]);
+
+       /* Look for the SMBus device. */
+       smbus_dev = pci_dev_find(0x1002, 0x4385);
+
+       if (!smbus_dev) {
+               smbus_dev = pci_dev_find(0x1022, 0x780b); /* AMD Hudson */
+               if (!smbus_dev) {
+                       msg_perr("ERROR: SMBus device not found. Not enabling SPI.\n");
+                       return ERROR_NONFATAL;
+               }
+       }
+
+       /* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
+       /* GPIO11/SPI_DO and GPIO12/SPI_DI status */
+       reg = pci_read_byte(smbus_dev, 0xAB);
+       reg &= 0xC0;
+       msg_pdbg("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO");
+       msg_pdbg("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI");
+       if (reg != 0x00) {
+               msg_pdbg("Not enabling SPI");
+               return 0;
+       }
+       /* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */
+       reg = pci_read_byte(smbus_dev, 0x83);
+       reg &= 0xC0;
+       msg_pdbg("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD");
+       msg_pdbg("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS");
+       /* SPI_HOLD is not used on all boards, filter it out. */
+       if ((reg & 0x80) != 0x00) {
+               msg_pdbg("Not enabling SPI");
+               return 0;
+       }
+       /* GPIO47/SPI_CLK status */
+       reg = pci_read_byte(smbus_dev, 0xA7);
+       reg &= 0x40;
+       msg_pdbg("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK");
+       if (reg != 0x00) {
+               msg_pdbg("Not enabling SPI");
+               return 0;
+       }
+
+       reg = pci_read_byte(dev, 0x40);
+       msg_pdbg("SB700 IMC is %sactive.\n", (reg & (1 << 7)) ? "" : "not ");
+       if (reg & (1 << 7)) {
+               /* If we touch any region used by the IMC, the IMC and the SPI
+                * interface will lock up, and the only way to recover is a
+                * hard reset, but that is a bad choice for a half-erased or
+                * half-written flash chip.
+                * There appears to be an undocumented register which can freeze
+                * or disable the IMC, but for now we want to play it safe.
+                */
+               msg_perr("The SB700 IMC is active and may interfere with SPI "
+                        "commands. Disabling write.\n");
+               /* FIXME: Should we only disable SPI writes, or will the lockup
+                * affect LPC/FWH chips as well?
+                */
+               programmer_may_write = 0;
+       }
+
+       /* Bring the FIFO to a clean state. */
+       reset_internal_fifo_pointer();
+
+       register_spi_programmer(&spi_programmer_sb600);
+       return 0;
+}
+
+#endif
diff --git a/serial.c b/serial.c
new file mode 100644 (file)
index 0000000..7443a3c
--- /dev/null
+++ b/serial.c
@@ -0,0 +1,309 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Urja Rannikko <urjaman@gmail.com>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <inttypes.h>
+#ifdef _WIN32
+#include <conio.h>
+#else
+#include <termios.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#endif
+#include "flash.h"
+#include "programmer.h"
+
+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((unsigned char)dev[0]) == 'c') &&
+           (tolower((unsigned char)dev[1]) == 'o') &&
+           (tolower((unsigned char)dev[2]) == 'm')) {
+               dev2 = malloc(strlen(dev) + 5);
+               if (!dev2) {
+                       msg_perr("Error: Out of memory: %s\n", strerror(errno));
+                       return -1;
+               }
+               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) {
+               msg_perr("Error: cannot open serial port: %s\n", strerror(errno));
+               return -1;
+       }
+       DCB dcb;
+       if (!GetCommState(fd, &dcb)) {
+               msg_perr("Error: Could not fetch serial port configuration: %s\n", strerror(errno));
+               return -1;
+       }
+       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: msg_perr("Error: Could not set baud rate: %s\n", strerror(errno));
+                        return -1;
+       }
+       dcb.ByteSize = 8;
+       dcb.Parity = NOPARITY;
+       dcb.StopBits = ONESTOPBIT;
+       if (!SetCommState(fd, &dcb)) {
+               msg_perr("Error: Could not change serial port configuration: %s\n", strerror(errno));
+               return -1;
+       }
+       return fd;
+#else
+       struct termios options;
+       int fd, i;
+       fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
+       if (fd < 0) {
+               msg_perr("Error: cannot open serial port: %s\n", strerror(errno));
+               return -1;
+       }
+       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);
+                       return -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_set_pin(enum SP_PIN pin, int val) {
+#ifdef _WIN32
+       DWORD ctl;
+
+       if(pin == PIN_TXD) {
+               ctl = val ? SETBREAK: CLRBREAK;
+       }
+       else if(pin == PIN_DTR) {
+               ctl = val ? SETDTR: CLRDTR;
+       }
+       else {
+               ctl = val ? SETRTS: CLRRTS;
+       }
+       EscapeCommFunction(sp_fd, ctl);
+#else
+       int ctl, s;
+
+       if(pin == PIN_TXD) {
+               ioctl(sp_fd, val ? TIOCSBRK : TIOCCBRK, 0);
+       }
+       else {
+               s = (pin == PIN_DTR) ? TIOCM_DTR : TIOCM_RTS;
+               ioctl(sp_fd, TIOCMGET, &ctl);
+
+               if (val) {
+                       ctl |= s;
+               }
+               else {
+                       ctl &= ~s;
+               }
+               ioctl(sp_fd, TIOCMSET, &ctl);
+       }
+#endif
+}
+
+int sp_get_pin(enum SP_PIN pin) {
+       int s;
+#ifdef _WIN32
+       DWORD ctl;
+
+       s = (pin == PIN_CTS) ? MS_CTS_ON : MS_DSR_ON;
+       GetCommModemStatus(sp_fd, &ctl);
+#else
+       int ctl;
+       s = (pin == PIN_CTS) ? TIOCM_CTS : TIOCM_DSR;
+       ioctl(sp_fd, TIOCMGET, &ctl);
+#endif
+
+       return ((ctl & s) ? 1 : 0);
+
+}
+
+void sp_flush_incoming(void)
+{
+#ifdef _WIN32
+       PurgeComm(sp_fd, PURGE_RXCLEAR);
+#else
+       tcflush(sp_fd, TCIFLUSH);
+#endif
+       return;
+}
+
+int serialport_shutdown(void *data)
+{
+#ifdef _WIN32
+       CloseHandle(sp_fd);
+#else
+       close(sp_fd);
+#endif
+       return 0;
+}
+
+int serialport_write(unsigned char *buf, unsigned int writecnt)
+{
+#ifdef _WIN32
+       DWORD tmp = 0;
+#else
+       ssize_t tmp = 0;
+#endif
+
+       while (writecnt > 0) {
+#ifdef _WIN32
+               WriteFile(sp_fd, buf, writecnt, &tmp, NULL);
+#else
+               tmp = write(sp_fd, buf, writecnt);
+#endif
+               if (tmp == -1) {
+                       msg_perr("Serial port write error!\n");
+                       return 1;
+               }
+               if (!tmp)
+                       msg_pdbg("Empty write\n");
+               writecnt -= tmp; 
+               buf += tmp;
+       }
+
+       return 0;
+}
+
+int serialport_read(unsigned char *buf, unsigned int readcnt)
+{
+#ifdef _WIN32
+       DWORD tmp = 0;
+#else
+       ssize_t tmp = 0;
+#endif
+
+       while (readcnt > 0) {
+#ifdef _WIN32
+               ReadFile(sp_fd, buf, readcnt, &tmp, NULL);
+#else
+               tmp = read(sp_fd, buf, readcnt);
+#endif
+               if (tmp == -1) {
+                       msg_perr("Serial port read error!\n");
+                       return 1;
+               }
+               if (!tmp)
+                       msg_pdbg("Empty read\n");
+               readcnt -= tmp;
+               buf += tmp;
+       }
+
+       return 0;
+}
diff --git a/serprog.c b/serprog.c
new file mode 100644 (file)
index 0000000..3529127
--- /dev/null
+++ b/serprog.c
@@ -0,0 +1,873 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009, 2011 Urja Rannikko <urjaman@gmail.com>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <termios.h>
+#include "flash.h"
+#include "programmer.h"
+#include "chipdrivers.h"
+
+#define MSGHEADER "serprog: "
+
+/*
+ * FIXME: This prototype was added to help reduce diffs for the shutdown
+ * registration patch, which shifted many lines of code to place
+ * serprog_shutdown() before serprog_init(). It should be removed soon.
+ */
+static int serprog_shutdown(void *data);
+
+#define S_ACK 0x06
+#define S_NAK 0x15
+#define S_CMD_NOP              0x00    /* No operation                                 */
+#define S_CMD_Q_IFACE          0x01    /* Query interface version                      */
+#define S_CMD_Q_CMDMAP         0x02    /* Query supported commands bitmap              */
+#define S_CMD_Q_PGMNAME                0x03    /* Query programmer name                        */
+#define S_CMD_Q_SERBUF         0x04    /* Query Serial Buffer Size                     */
+#define S_CMD_Q_BUSTYPE                0x05    /* Query supported bustypes                     */
+#define S_CMD_Q_CHIPSIZE       0x06    /* Query supported chipsize (2^n format)        */
+#define S_CMD_Q_OPBUF          0x07    /* Query operation buffer size                  */
+#define S_CMD_Q_WRNMAXLEN      0x08    /* Query opbuf-write-N maximum length           */
+#define S_CMD_R_BYTE           0x09    /* Read a single byte                           */
+#define S_CMD_R_NBYTES         0x0A    /* Read n bytes                                 */
+#define S_CMD_O_INIT           0x0B    /* Initialize operation buffer                  */
+#define S_CMD_O_WRITEB         0x0C    /* Write opbuf: Write byte with address         */
+#define S_CMD_O_WRITEN         0x0D    /* Write to opbuf: Write-N                      */
+#define S_CMD_O_DELAY          0x0E    /* Write opbuf: udelay                          */
+#define S_CMD_O_EXEC           0x0F    /* Execute operation buffer                     */
+#define S_CMD_SYNCNOP          0x10    /* Special no-operation that returns NAK+ACK    */
+#define S_CMD_Q_RDNMAXLEN      0x11    /* Query read-n maximum length                  */
+#define S_CMD_S_BUSTYPE                0x12    /* Set used bustype(s).                         */
+#define S_CMD_O_SPIOP          0x13    /* Perform SPI operation.                       */
+
+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 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
+       combined write-n operation */
+static uint32_t sp_write_n_addr;
+/* The maximum length of an write_n operation; 0 = write-n not supported */
+static uint32_t sp_max_write_n = 0;
+/* The maximum length of a read_n operation; 0 = 2^24 */
+static uint32_t sp_max_read_n = 0;
+
+/* A malloc'd buffer for combining the operation's data
+       and a counter that tells how much data is there. */
+static uint8_t *sp_write_n_buf;
+static uint32_t sp_write_n_bytes = 0;
+
+/* sp_streamed_* used for flow control checking */
+static int sp_streamed_transmit_ops = 0;
+static int sp_streamed_transmit_bytes = 0;
+
+/* sp_opbuf_usage used for counting the amount of
+       on-device operation buffer used */
+static int sp_opbuf_usage = 0;
+/* if true causes sp_docommand to automatically check
+       whether the command is supported before doing it */
+static int sp_check_avail_automatic = 0;
+
+static int sp_opensocket(char *ip, unsigned int port)
+{
+       int flag = 1;
+       struct hostent *hostPtr = NULL;
+       union { struct sockaddr_in si; struct sockaddr s; } sp = {};
+       int sock;
+       msg_pdbg(MSGHEADER "IP %s port %d\n", ip, port);
+       sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (sock < 0) {
+               msg_perr("Error: serprog cannot open socket: %s\n", strerror(errno));
+               return -1;
+       }
+       hostPtr = gethostbyname(ip);
+       if (NULL == hostPtr) {
+               hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET);
+               if (NULL == hostPtr) {
+                       msg_perr("Error: cannot resolve %s\n", ip);
+                       return -1;
+               }
+       }
+       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);
+               msg_perr("Error: serprog cannot connect: %s\n", strerror(errno));
+               return -1;
+       }
+       /* We are latency limited, and sometimes do write-write-read    *
+        * (write-n) - so enable TCP_NODELAY.                           */
+       setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
+       return sock;
+}
+
+static int sp_sync_read_timeout(int loops)
+{
+       int i;
+       unsigned char c;
+       for (i = 0; i < loops; i++) {
+               ssize_t rv;
+               rv = read(sp_fd, &c, 1);
+               if (rv == 1)
+                       return c;
+               if ((rv == -1) && (errno != EAGAIN))
+                       sp_die("read");
+               usleep(10 * 1000);      /* 10ms units */
+       }
+       return -1;
+}
+
+/* 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  *
+ * serial operations, though not such a big issue as the first thing to   *
+ * do is synchronize (eg. check that device is alive).                   */
+static void sp_synchronize(void)
+{
+       int i;
+       int flags = fcntl(sp_fd, F_GETFL);
+       unsigned char buf[8];
+       flags |= O_NONBLOCK;
+       fcntl(sp_fd, F_SETFL, flags);
+       /* First sends 8 NOPs, then flushes the return data - should cause *
+        * the device serial parser to get to a sane state, unless if it   *
+        * is waiting for a real long write-n.                             */
+       memset(buf, S_CMD_NOP, 8);
+       if (write(sp_fd, buf, 8) != 8)
+               sp_die("flush write");
+       /* A second should be enough to get all the answers to the buffer */
+       usleep(1000 * 1000);
+       sp_flush_incoming();
+
+       /* Then try up to 8 times to send syncnop and get the correct special *
+        * return of NAK+ACK. Timing note: up to 10 characters, 10*50ms =     *
+        * up to 500ms per try, 8*0.5s = 4s; +1s (above) = up to 5s sync      *
+        * attempt, ~1s if immediate success.                                 */
+       for (i = 0; i < 8; i++) {
+               int n;
+               unsigned char c = S_CMD_SYNCNOP;
+               if (write(sp_fd, &c, 1) != 1)
+                       sp_die("sync write");
+               msg_pdbg(".");
+               fflush(stdout);
+               for (n = 0; n < 10; n++) {
+                       c = sp_sync_read_timeout(5);    /* wait up to 50ms */
+                       if (c != S_NAK)
+                               continue;
+                       c = sp_sync_read_timeout(2);
+                       if (c != S_ACK)
+                               continue;
+                       c = S_CMD_SYNCNOP;
+                       if (write(sp_fd, &c, 1) != 1)
+                               sp_die("sync write");
+                       c = sp_sync_read_timeout(50);
+                       if (c != S_NAK)
+                               break;  /* fail */
+                       c = sp_sync_read_timeout(10);
+                       if (c != S_ACK)
+                               break;  /* fail */
+                       /* Ok, synchronized; back to blocking reads and return. */
+                       flags &= ~O_NONBLOCK;
+                       fcntl(sp_fd, F_SETFL, flags);
+                       msg_pdbg("\n");
+                       return;
+               }
+       }
+       msg_perr("Error: cannot synchronize protocol "
+               "- check communications and reset device?\n");
+       exit(1);
+}
+
+static int sp_check_commandavail(uint8_t command)
+{
+       int byteoffs, bitoffs;
+       byteoffs = command / 8;
+       bitoffs = command % 8;
+       return (sp_cmdmap[byteoffs] & (1 << bitoffs)) ? 1 : 0;
+}
+
+static int sp_automatic_cmdcheck(uint8_t cmd)
+{
+       if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
+               msg_pdbg("Warning: Automatic command availability check failed "
+                        "for cmd 0x%x - won't execute cmd\n", cmd);
+               return 1;
+               }
+       return 0;
+}
+
+static int sp_docommand(uint8_t command, uint32_t parmlen,
+                       uint8_t *params, uint32_t retlen, void *retparms)
+{
+       unsigned char c;
+       if (sp_automatic_cmdcheck(command))
+               return 1;
+       if (write(sp_fd, &command, 1) != 1) {
+               msg_perr("Error: cannot write op code: %s\n", strerror(errno));
+               return 1;
+       }
+       if (write(sp_fd, params, parmlen) != (parmlen)) {
+               msg_perr("Error: cannot write parameters: %s\n", strerror(errno));
+               return 1;
+       }
+       if (read(sp_fd, &c, 1) != 1) {
+               msg_perr("Error: cannot read from device: %s\n", strerror(errno));
+               return 1;
+       }
+       if (c == S_NAK)
+               return 1;
+       if (c != S_ACK) {
+               msg_perr("Error: invalid response 0x%02X from device\n", c);
+               return 1;
+       }
+       if (retlen) {
+               int rd_bytes = 0;
+               do {
+                       int r;
+                       r = read(sp_fd, retparms + rd_bytes,
+                                retlen - rd_bytes);
+                       if (r <= 0) {
+                               msg_perr("Error: cannot read return parameters: %s\n", strerror(errno));
+                               return 1;
+                       }
+                       rd_bytes += r;
+               } while (rd_bytes != retlen);
+       }
+       return 0;
+}
+
+static void sp_flush_stream(void)
+{
+       if (sp_streamed_transmit_ops)
+               do {
+                       unsigned char c;
+                       if (read(sp_fd, &c, 1) != 1) {
+                               sp_die("Error: cannot read from device (flushing stream)");
+                       }
+                       if (c == S_NAK) {
+                               msg_perr("Error: NAK to a stream buffer operation\n");
+                               exit(1);
+                       }
+                       if (c != S_ACK) {
+                               msg_perr("Error: Invalid reply 0x%02X from device\n", c);
+                               exit(1);
+                       }
+               } while (--sp_streamed_transmit_ops);
+       sp_streamed_transmit_ops = 0;
+       sp_streamed_transmit_bytes = 0;
+}
+
+static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms)
+{
+       uint8_t *sp;
+       if (sp_automatic_cmdcheck(cmd))
+               return 1;
+       sp = malloc(1 + parmlen);
+       if (!sp) sp_die("Error: cannot malloc command buffer");
+       sp[0] = cmd;
+       memcpy(&(sp[1]), parms, parmlen);
+       if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size))
+               sp_flush_stream();
+       if (write(sp_fd, sp, 1 + parmlen) != (1 + parmlen))
+               sp_die("Error: cannot write command");
+       free(sp);
+       sp_streamed_transmit_ops += 1;
+       sp_streamed_transmit_bytes += 1 + parmlen;
+       return 0;
+}
+
+static int serprog_spi_send_command(struct flashctx *flash,
+                                   unsigned int writecnt, unsigned int readcnt,
+                                   const unsigned char *writearr,
+                                   unsigned char *readarr);
+static int serprog_spi_read(struct flashctx *flash, uint8_t *buf,
+                           unsigned int start, unsigned int len);
+static struct spi_programmer spi_programmer_serprog = {
+       .type           = SPI_CONTROLLER_SERPROG,
+       .max_data_read  = MAX_DATA_READ_UNLIMITED,
+       .max_data_write = MAX_DATA_WRITE_UNLIMITED,
+       .command        = serprog_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = serprog_spi_read,
+       .write_256      = default_spi_write_256,
+       .write_aai      = default_spi_write_aai,
+};
+
+static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
+                               chipaddr addr);
+static uint8_t serprog_chip_readb(const struct flashctx *flash,
+                                 const chipaddr addr);
+static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
+                              const chipaddr addr, size_t len);
+static const struct par_programmer par_programmer_serprog = {
+               .chip_readb             = serprog_chip_readb,
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = serprog_chip_readn,
+               .chip_writeb            = serprog_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+static enum chipbustype serprog_buses_supported = BUS_NONE;
+
+int serprog_init(void)
+{
+       uint16_t iface;
+       unsigned char pgmname[17];
+       unsigned char rbuf[3];
+       unsigned char c;
+       char *device;
+       char *baudport;
+       int have_device = 0;
+
+       /* the parameter is either of format "dev=/dev/device:baud" or "ip=ip:port" */
+       device = extract_programmer_param("dev");
+       if (device && strlen(device)) {
+               baudport = strstr(device, ":");
+               if (baudport) {
+                       /* Split device from baudrate. */
+                       *baudport = '\0';
+                       baudport++;
+               }
+               if (!baudport || !strlen(baudport)) {
+                       msg_perr("Error: No baudrate specified.\n"
+                                "Use flashrom -p serprog:dev=/dev/device:baud\n");
+                       free(device);
+                       return 1;
+               }
+               if (strlen(device)) {
+                       sp_fd = sp_openserport(device, atoi(baudport));
+                       if (sp_fd < 0) {
+                               free(device);
+                               return 1;
+                       }
+                       have_device++;
+               }
+       }
+       if (device && !strlen(device)) {
+               msg_perr("Error: No device specified.\n"
+                        "Use flashrom -p serprog:dev=/dev/device:baud\n");
+               free(device);
+               return 1;
+       }
+       free(device);
+
+       device = extract_programmer_param("ip");
+       if (have_device && device) {
+               msg_perr("Error: Both host and device specified.\n"
+                        "Please use either dev= or ip= but not both.\n");
+               free(device);
+               return 1;
+       }
+       if (device && strlen(device)) {
+               baudport = strstr(device, ":");
+               if (baudport) {
+                       /* Split host from port. */
+                       *baudport = '\0';
+                       baudport++;
+               }
+               if (!baudport || !strlen(baudport)) {
+                       msg_perr("Error: No port specified.\n"
+                                "Use flashrom -p serprog:ip=ipaddr:port\n");
+                       free(device);
+                       return 1;
+               }
+               if (strlen(device)) {
+                       sp_fd = sp_opensocket(device, atoi(baudport));
+                       if (sp_fd < 0) {
+                               free(device);
+                               return 1;
+                       }
+                       have_device++;
+               }
+       }
+       if (device && !strlen(device)) {
+               msg_perr("Error: No host specified.\n"
+                        "Use flashrom -p serprog:ip=ipaddr:port\n");
+               free(device);
+               return 1;
+       }
+       free(device);
+
+       if (!have_device) {
+               msg_perr("Error: Neither host nor device specified.\n"
+                        "Use flashrom -p serprog:dev=/dev/device:baud or "
+                        "flashrom -p serprog:ip=ipaddr:port\n");
+               return 1;
+       }
+
+       if (register_shutdown(serprog_shutdown, NULL))
+               return 1;
+
+       msg_pdbg(MSGHEADER "connected - attempting to synchronize\n");
+
+       sp_check_avail_automatic = 0;
+
+       sp_synchronize();
+
+       msg_pdbg(MSGHEADER "Synchronized\n");
+
+       if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
+               msg_perr("Error: NAK to query interface version\n");
+               return 1;
+       }
+
+       if (iface != 1) {
+               msg_perr("Error: Unknown interface version: %d\n", iface);
+               return 1;
+       }
+
+       msg_pdbg(MSGHEADER "Interface version ok.\n");
+
+       if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
+               msg_perr("Error: query command map not supported\n");
+               return 1;
+       }
+
+       sp_check_avail_automatic = 1;
+
+       /* FIXME: This assumes that serprog device bustypes are always
+        * identical with flashrom bustype enums and that they all fit
+        * in a single byte.
+        */
+       if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
+               msg_perr("Warning: NAK to query supported buses\n");
+               c = BUS_NONSPI; /* A reasonable default for now. */
+       }
+       serprog_buses_supported = c;
+
+       msg_pdbg(MSGHEADER "Bus support: parallel=%s, LPC=%s, FWH=%s, SPI=%s\n",
+                (c & BUS_PARALLEL) ? "on" : "off",
+                (c & BUS_LPC) ? "on" : "off",
+                (c & BUS_FWH) ? "on" : "off",
+                (c & BUS_SPI) ? "on" : "off");
+       /* Check for the minimum operational set of commands. */
+       if (serprog_buses_supported & BUS_SPI) {
+               uint8_t bt = BUS_SPI;
+               if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
+                       msg_perr("Error: SPI operation not supported while the "
+                                "bustype is SPI\n");
+                       return 1;
+               }
+               if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
+                       return 1;
+               /* Success of any of these commands is optional. We don't need
+                  the programmer to tell us its limits, but if it doesn't, we
+                  will assume stuff, so it's in the programmers best interest
+                  to tell us. */
+               if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
+                       uint32_t v;
+                       v = ((unsigned int)(rbuf[0]) << 0);
+                       v |= ((unsigned int)(rbuf[1]) << 8);
+                       v |= ((unsigned int)(rbuf[2]) << 16);
+                       if (v == 0)
+                               v = (1 << 24) - 1; /* SPI-op maximum. */
+                       spi_programmer_serprog.max_data_write = v;
+                       msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", v);
+               }
+               if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
+                       uint32_t v;
+                       v = ((unsigned int)(rbuf[0]) << 0);
+                       v |= ((unsigned int)(rbuf[1]) << 8);
+                       v |= ((unsigned int)(rbuf[2]) << 16);
+                       if (v == 0)
+                               v = (1 << 24) - 1; /* SPI-op maximum. */
+                       spi_programmer_serprog.max_data_read = v;
+                       msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
+               }
+               bt = serprog_buses_supported;
+               if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
+                       return 1;
+       }
+
+       if (serprog_buses_supported & BUS_NONSPI) {
+               if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
+                       msg_perr("Error: Initialize operation buffer "
+                                "not supported\n");
+                       return 1;
+               }
+
+               if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
+                       msg_perr("Error: Write to opbuf: "
+                                "delay not supported\n");
+                       return 1;
+               }
+
+               /* S_CMD_O_EXEC availability checked later. */
+
+               if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
+                       msg_perr("Error: Single byte read not supported\n");
+                       return 1;
+               }
+               /* This could be translated to single byte reads (if missing),
+                * but now we don't support that. */
+               if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
+                       msg_perr("Error: Read n bytes not supported\n");
+                       return 1;
+               }
+               if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
+                       msg_perr("Error: Write to opbuf: "
+                                "write byte not supported\n");
+                       return 1;
+               }
+
+               if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
+                       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);
+                       if (!sp_max_write_n) {
+                               sp_max_write_n = (1 << 24);
+                       }
+                       msg_pdbg(MSGHEADER "Maximum write-n length is %d\n",
+                                sp_max_write_n);
+                       sp_write_n_buf = malloc(sp_max_write_n);
+                       if (!sp_write_n_buf) {
+                               msg_perr("Error: cannot allocate memory for "
+                                        "Write-n buffer\n");
+                               return 1;
+                       }
+                       sp_write_n_bytes = 0;
+               }
+
+               if (sp_check_commandavail(S_CMD_Q_RDNMAXLEN) &&
+                   (sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf) == 0)) {
+                       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);
+                       msg_pdbg(MSGHEADER "Maximum read-n length is %d\n",
+                                sp_max_read_n ? sp_max_read_n : (1 << 24));
+               } else {
+                       msg_pdbg(MSGHEADER "Maximum read-n length "
+                                "not reported\n");
+                       sp_max_read_n = 0;
+               }
+
+       }
+
+       if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
+               msg_perr("Warning: NAK to query programmer name\n");
+               strcpy((char *)pgmname, "(unknown)");
+       }
+       pgmname[16] = 0;
+       msg_pinfo(MSGHEADER "Programmer name is \"%s\"\n", pgmname);
+
+       if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) {
+               msg_perr("Warning: NAK to query serial buffer size\n");
+       }
+       msg_pdbg(MSGHEADER "Serial buffer size is %d\n",
+                    sp_device_serbuf_size);
+
+       if (sp_check_commandavail(S_CMD_O_INIT)) {
+               /* This would be inconsistent. */
+               if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
+                       msg_perr("Error: Execute operation buffer not "
+                                "supported\n");
+                       return 1;
+               }
+
+               if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
+                       msg_perr("Error: NAK to initialize operation buffer\n");
+                       return 1;
+               }
+
+               if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
+                   &sp_device_opbuf_size)) {
+                       msg_perr("Warning: NAK to query operation buffer "
+                                "size\n");
+               }
+               msg_pdbg(MSGHEADER "operation buffer size is %d\n",
+                        sp_device_opbuf_size);
+       }
+
+       sp_prev_was_write = 0;
+       sp_streamed_transmit_ops = 0;
+       sp_streamed_transmit_bytes = 0;
+       sp_opbuf_usage = 0;
+       if (serprog_buses_supported & BUS_SPI)
+               register_spi_programmer(&spi_programmer_serprog);
+       if (serprog_buses_supported & BUS_NONSPI)
+               register_par_programmer(&par_programmer_serprog,
+                                       serprog_buses_supported & BUS_NONSPI);
+       return 0;
+}
+
+/* Move an in flashrom buffer existing write-n operation to    *
+ * the on-device operation buffer.                             */
+static void sp_pass_writen(void)
+{
+       unsigned char header[7];
+       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))
+               sp_flush_stream();
+       /* In case it's just a single byte send it as a single write. */
+       if (sp_write_n_bytes == 1) {
+               sp_write_n_bytes = 0;
+               header[0] = (sp_write_n_addr >> 0) & 0xFF;
+               header[1] = (sp_write_n_addr >> 8) & 0xFF;
+               header[2] = (sp_write_n_addr >> 16) & 0xFF;
+               header[3] = sp_write_n_buf[0];
+               sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header);
+               sp_opbuf_usage += 5;
+               return;
+       }
+       header[0] = S_CMD_O_WRITEN;
+       header[1] = (sp_write_n_bytes >> 0) & 0xFF;
+       header[2] = (sp_write_n_bytes >> 8) & 0xFF;
+       header[3] = (sp_write_n_bytes >> 16) & 0xFF;
+       header[4] = (sp_write_n_addr >> 0) & 0xFF;
+       header[5] = (sp_write_n_addr >> 8) & 0xFF;
+       header[6] = (sp_write_n_addr >> 16) & 0xFF;
+       if (write(sp_fd, header, 7) != 7)
+               sp_die("Error: cannot write write-n command\n");
+       if (write(sp_fd, sp_write_n_buf, sp_write_n_bytes) !=
+           sp_write_n_bytes)
+               sp_die("Error: cannot write write-n data");
+       sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
+       sp_streamed_transmit_ops += 1;
+       sp_opbuf_usage += 7 + sp_write_n_bytes;
+       sp_write_n_bytes = 0;
+       sp_prev_was_write = 0;
+}
+
+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, NULL);
+       msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n",
+                    sp_opbuf_usage);
+       sp_opbuf_usage = 0;
+       sp_prev_was_write = 0;
+       return;
+}
+
+static void sp_execute_opbuf(void)
+{
+       sp_execute_opbuf_noflush();
+       sp_flush_stream();
+}
+
+static int serprog_shutdown(void *data)
+{
+       msg_pspew("%s\n", __func__);
+       if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+               sp_execute_opbuf();
+       close(sp_fd);
+       if (sp_max_write_n)
+               free(sp_write_n_buf);
+       return 0;
+}
+
+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 probably fail.                                      */
+               msg_pdbg(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
+       }
+}
+
+static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
+                               chipaddr addr)
+{
+       msg_pspew("%s\n", __func__);
+       if (sp_max_write_n) {
+               if ((sp_prev_was_write)
+                   && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
+                       sp_write_n_buf[sp_write_n_bytes++] = val;
+               } else {
+                       if ((sp_prev_was_write) && (sp_write_n_bytes))
+                               sp_pass_writen();
+                       sp_prev_was_write = 1;
+                       sp_write_n_addr = addr;
+                       sp_write_n_bytes = 1;
+                       sp_write_n_buf[0] = val;
+               }
+               sp_check_opbuf_usage(7 + sp_write_n_bytes);
+               if (sp_write_n_bytes >= sp_max_write_n)
+                       sp_pass_writen();
+       } else {
+               /* We will have to do single writeb ops. */
+               unsigned char writeb_parm[4];
+               sp_check_opbuf_usage(6);
+               writeb_parm[0] = (addr >> 0) & 0xFF;
+               writeb_parm[1] = (addr >> 8) & 0xFF;
+               writeb_parm[2] = (addr >> 16) & 0xFF;
+               writeb_parm[3] = val;
+               sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm);
+               sp_opbuf_usage += 5;
+       }
+}
+
+static uint8_t serprog_chip_readb(const struct flashctx *flash,
+                                 const chipaddr addr)
+{
+       unsigned char c;
+       unsigned char buf[3];
+       /* Will stream the read operation - eg. add it to the stream buffer, *
+        * then flush the buffer, then read the read answer.                 */
+       if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+               sp_execute_opbuf_noflush();
+       buf[0] = ((addr >> 0) & 0xFF);
+       buf[1] = ((addr >> 8) & 0xFF);
+       buf[2] = ((addr >> 16) & 0xFF);
+       sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf);
+       sp_flush_stream();
+       if (read(sp_fd, &c, 1) != 1)
+               sp_die("readb byteread");
+       msg_pspew("%s addr=0x%lx returning 0x%02X\n", __func__, addr, c);
+       return c;
+}
+
+/* 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];
+       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();
+       sbuf[0] = ((addr >> 0) & 0xFF);
+       sbuf[1] = ((addr >> 8) & 0xFF);
+       sbuf[2] = ((addr >> 16) & 0xFF);
+       sbuf[3] = ((len >> 0) & 0xFF);
+       sbuf[4] = ((len >> 8) & 0xFF);
+       sbuf[5] = ((len >> 16) & 0xFF);
+       sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
+       sp_flush_stream();
+       do {
+               int r = read(sp_fd, buf + rd_bytes, len - rd_bytes);
+               if (r <= 0)
+                       sp_die("Error: cannot read read-n data");
+               rd_bytes += r;
+       } while (rd_bytes != len);
+       return;
+}
+
+/* The externally called version that makes sure that max_read_n is obeyed. */
+static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
+                              const chipaddr addr, size_t len)
+{
+       size_t lenm = len;
+       chipaddr addrm = addr;
+       while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
+               sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n);
+               addrm += sp_max_read_n;
+               lenm -= sp_max_read_n;
+       }
+       if (lenm)
+               sp_do_read_n(&(buf[addrm-addr]), addrm, lenm);
+}
+
+void serprog_delay(int usecs)
+{
+       unsigned char buf[4];
+       msg_pspew("%s usecs=%d\n", __func__, usecs);
+       if (!sp_check_commandavail(S_CMD_O_DELAY)) {
+               msg_pdbg("Note: serprog_delay used, but the programmer doesn't "
+                        "support delay\n");
+               internal_delay(usecs);
+               return;
+       }
+       if ((sp_max_write_n) && (sp_write_n_bytes))
+               sp_pass_writen();
+       sp_check_opbuf_usage(5);
+       buf[0] = ((usecs >> 0) & 0xFF);
+       buf[1] = ((usecs >> 8) & 0xFF);
+       buf[2] = ((usecs >> 16) & 0xFF);
+       buf[3] = ((usecs >> 24) & 0xFF);
+       sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
+       sp_opbuf_usage += 5;
+       sp_prev_was_write = 0;
+}
+
+static int serprog_spi_send_command(struct flashctx *flash,
+                                   unsigned int writecnt, unsigned int readcnt,
+                                   const unsigned char *writearr,
+                                   unsigned char *readarr)
+{
+       unsigned char *parmbuf;
+       int ret;
+       msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
+       if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+               sp_execute_opbuf();
+       parmbuf = malloc(writecnt + 6);
+       if (!parmbuf)
+               sp_die("Error: cannot malloc SPI send param buffer");
+       parmbuf[0] = (writecnt >> 0) & 0xFF;
+       parmbuf[1] = (writecnt >> 8) & 0xFF;
+       parmbuf[2] = (writecnt >> 16) & 0xFF;
+       parmbuf[3] = (readcnt >> 0) & 0xFF;
+       parmbuf[4] = (readcnt >> 8) & 0xFF;
+       parmbuf[5] = (readcnt >> 16) & 0xFF;
+       memcpy(parmbuf + 6, writearr, writecnt);
+       ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
+                          readarr);
+       free(parmbuf);
+       return ret;
+}
+
+/* FIXME: This function is optimized so that it does not split each transaction
+ * into chip page_size long blocks unnecessarily like spi_read_chunked. This has
+ * the advantage that it is much faster for most chips, but breaks those with
+ * non-contiguous address space (like AT45DB161D). When spi_read_chunked is
+ * fixed this method can be removed. */
+static int serprog_spi_read(struct flashctx *flash, uint8_t *buf,
+                           unsigned int start, unsigned int len)
+{
+       unsigned int i, cur_len;
+       const unsigned int max_read = spi_programmer_serprog.max_data_read;
+       for (i = 0; i < len; i += cur_len) {
+               int ret;
+               cur_len = min(max_read, (len - i));
+               ret = spi_nbyte_read(flash, start + i, buf + i, cur_len);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
diff --git a/sfdp.c b/sfdp.c
new file mode 100644 (file)
index 0000000..708b66b
--- /dev/null
+++ b/sfdp.c
@@ -0,0 +1,394 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011-2012 Stefan Tauner
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "flash.h"
+#include "spi.h"
+#include "chipdrivers.h"
+
+static int spi_sfdp_read_sfdp_chunk(struct flashctx *flash, uint32_t address, uint8_t *buf, int len)
+{
+       int i, ret;
+       uint8_t *newbuf;
+       const unsigned char cmd[JEDEC_SFDP_OUTSIZE] = {
+               JEDEC_SFDP,
+               (address >> 16) & 0xff,
+               (address >> 8) & 0xff,
+               (address >> 0) & 0xff,
+               /* FIXME: the following dummy byte explodes on some programmers.
+                * One workaround is to read the dummy byte
+                * instead and discard its value.
+                */
+               0
+       };
+       msg_cspew("%s: addr=0x%x, len=%d, data:\n", __func__, address, len);
+       newbuf = malloc(len + 1);
+       if (!newbuf)
+               return SPI_PROGRAMMER_ERROR;
+       ret = spi_send_command(flash, sizeof(cmd) - 1, len + 1, cmd, newbuf);
+       memmove(buf, newbuf + 1, len);
+       free(newbuf);
+       if (ret)
+               return ret;
+       for (i = 0; i < len; i++)
+               msg_cspew(" 0x%02x", buf[i]);
+       msg_cspew("\n");
+       return 0;
+}
+
+static int spi_sfdp_read_sfdp(struct flashctx *flash, uint32_t address, uint8_t *buf, int len)
+{
+       /* FIXME: There are different upper bounds for the number of bytes to
+        * read on the various programmers (even depending on the rest of the
+        * structure of the transaction). 2 is a safe bet. */
+       int maxstep = 2;
+       int ret = 0;
+       while (len > 0) {
+               int step = min(len, maxstep);
+               ret = spi_sfdp_read_sfdp_chunk(flash, address, buf, step);
+               if (ret)
+                       return ret;
+               address += step;
+               buf += step;
+               len -= step;
+       }
+       return ret;
+}
+
+struct sfdp_tbl_hdr {
+       uint8_t id;
+       uint8_t v_minor;
+       uint8_t v_major;
+       uint8_t len;
+       uint32_t ptp; /* 24b pointer */
+};
+
+static int sfdp_add_uniform_eraser(struct flashctx *flash, uint8_t opcode, uint32_t block_size)
+{
+       int i;
+       uint32_t total_size = flash->total_size * 1024;
+       erasefunc_t *erasefn = spi_get_erasefn_from_opcode(opcode);
+
+       if (erasefn == NULL || total_size == 0 || block_size == 0 ||
+           total_size % block_size != 0) {
+               msg_cdbg("%s: invalid input, please report to "
+                        "flashrom@flashrom.org\n", __func__);
+               return 1;
+       }
+
+       for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
+               struct block_eraser *eraser = &flash->block_erasers[i];
+               /* Check for duplicates (including (some) non-uniform ones). */
+               if (eraser->eraseblocks[0].size == block_size &&
+                   eraser->block_erase == erasefn) {
+                       msg_cdbg2("  Tried to add a duplicate block eraser: "
+                                 "%d x %d B with opcode 0x%02x.\n",
+                                 total_size/block_size, block_size, opcode);
+                       return 1;
+               }
+               if (eraser->eraseblocks[0].size != 0 ||
+                   eraser->block_erase != NULL) {
+                       msg_cspew("  Block Eraser %d is already occupied.\n",
+                                 i);
+                       continue;
+               }
+
+               eraser->block_erase = erasefn;
+               eraser->eraseblocks[0].size = block_size;
+               eraser->eraseblocks[0].count = total_size/block_size;
+               msg_cdbg2("  Block eraser %d: %d x %d B with opcode "
+                         "0x%02x\n", i, total_size/block_size, block_size,
+                         opcode);
+               return 0;
+       }
+       msg_cinfo("%s: Not enough space to store another eraser (i=%d)."
+                 " Please report this at flashrom@flashrom.org\n",
+                 __func__, i);
+       return 1;
+}
+
+static int sfdp_fill_flash(struct flashctx *flash, uint8_t *buf, uint16_t len)
+{
+       uint8_t opcode_4k_erase = 0xFF;
+       uint32_t tmp32;
+       uint8_t tmp8;
+       uint32_t total_size; /* in bytes */
+       uint32_t block_size;
+       int j;
+
+       msg_cdbg("Parsing JEDEC flash parameter table... ");
+       if (len != 9 * 4 && len != 4 * 4) {
+               msg_cdbg("%s: len out of spec\n", __func__);
+               return 1;
+       }
+       msg_cdbg2("\n");
+       
+       /* 1. double word */
+       tmp32 =  ((unsigned int)buf[(4 * 0) + 0]);
+       tmp32 |= ((unsigned int)buf[(4 * 0) + 1]) << 8;
+       tmp32 |= ((unsigned int)buf[(4 * 0) + 2]) << 16;
+       tmp32 |= ((unsigned int)buf[(4 * 0) + 3]) << 24;
+
+       tmp8 = (tmp32 >> 17) & 0x3;
+       switch (tmp8) {
+       case 0x0:
+               msg_cdbg2("  3-Byte only addressing.\n");
+               break;
+       case 0x1:
+               msg_cdbg2("  3-Byte (and optionally 4-Byte) addressing.\n");
+               break;
+       case 0x2:
+               msg_cdbg("  4-Byte only addressing (not supported by "
+                        "flashrom).\n");
+               return 1;
+       default:
+               msg_cdbg("  Required addressing mode (0x%x) not supported.\n",
+                        tmp8);
+               return 1;
+       }
+
+       msg_cdbg2("  Status register is ");
+       if (tmp32 & (1 << 3)) {
+               msg_cdbg2("volatile and writes to the status register have to "
+                         "be enabled with ");
+               if (tmp32 & (1 << 4)) {
+                       flash->feature_bits = FEATURE_WRSR_WREN;
+                       msg_cdbg2("WREN (0x06).\n");
+               } else {
+                       flash->feature_bits = FEATURE_WRSR_EWSR;
+                       msg_cdbg2("EWSR (0x50).\n");
+               }
+       } else {
+               msg_cdbg2("non-volatile and the standard does not allow "
+                         "vendors to tell us whether EWSR/WREN is needed for "
+                         "status register writes - assuming EWSR.\n");
+                       flash->feature_bits = FEATURE_WRSR_EWSR;
+               }
+
+       msg_cdbg2("  Write chunk size is ");
+       if (tmp32 & (1 << 2)) {
+               msg_cdbg2("at least 64 B.\n");
+               flash->page_size = 64;
+               flash->write = spi_chip_write_256;
+       } else {
+               msg_cdbg2("1 B only.\n");
+               flash->page_size = 256;
+               flash->write = spi_chip_write_1;
+       }
+
+       if ((tmp32 & 0x3) == 0x1) {
+               opcode_4k_erase = (tmp32 >> 8) & 0xFF;
+               msg_cspew("  4kB erase opcode is 0x%02x.\n", opcode_4k_erase);
+               /* add the eraser later, because we don't know total_size yet */
+       } else
+               msg_cspew("  4kB erase opcode is not defined.\n");
+
+       /* 2. double word */
+       tmp32 =  ((unsigned int)buf[(4 * 1) + 0]);
+       tmp32 |= ((unsigned int)buf[(4 * 1) + 1]) << 8;
+       tmp32 |= ((unsigned int)buf[(4 * 1) + 2]) << 16;
+       tmp32 |= ((unsigned int)buf[(4 * 1) + 3]) << 24;
+
+       if (tmp32 & (1 << 31)) {
+               msg_cdbg("Flash chip size >= 4 Gb/512 MB not supported.\n");
+               return 1;
+       }
+       total_size = ((tmp32 & 0x7FFFFFFF) + 1) / 8;
+       flash->total_size = total_size / 1024;
+       msg_cdbg2("  Flash chip size is %d kB.\n", flash->total_size);
+       if (total_size > (1 << 24)) {
+               msg_cdbg("Flash chip size is bigger than what 3-Byte addressing "
+                        "can access.\n");
+               return 1;
+       }
+
+       if (opcode_4k_erase != 0xFF)
+               sfdp_add_uniform_eraser(flash, opcode_4k_erase, 4 * 1024);
+
+       /* FIXME: double words 3-7 contain unused fast read information */
+
+       if (len == 4 * 4) {
+               msg_cdbg("  It seems like this chip supports the preliminary "
+                        "Intel version of SFDP, skipping processing of double "
+                        "words 3-9.\n");
+               goto done;
+       }
+
+       /* 8. double word */
+       for (j = 0; j < 4; j++) {
+               /* 7 double words from the start + 2 bytes for every eraser */
+               tmp8 = buf[(4 * 7) + (j * 2)];
+               msg_cspew("   Erase Sector Type %d Size: 0x%02x\n", j + 1,
+                         tmp8);
+               if (tmp8 == 0) {
+                       msg_cspew("  Erase Sector Type %d is unused.\n", j);
+                       continue;
+               }
+               if (tmp8 >= 31) {
+                       msg_cdbg2("  Block size of erase Sector Type %d (2^%d) "
+                                "is too big for flashrom.\n", j, tmp8);
+                       continue;
+               }
+               block_size = 1 << (tmp8); /* block_size = 2 ^ field */
+
+               tmp8 = buf[(4 * 7) + (j * 2) + 1];
+               msg_cspew("   Erase Sector Type %d Opcode: 0x%02x\n", j + 1,
+                         tmp8);
+               sfdp_add_uniform_eraser(flash, tmp8, block_size);
+       }
+
+done:
+       msg_cdbg("done.\n");
+       return 0;
+}
+
+int probe_spi_sfdp(struct flashctx *flash)
+{
+       int ret = 0;
+       uint8_t buf[8];
+       uint32_t tmp32;
+       uint8_t nph;
+       /* need to limit the table loop by comparing i to uint8_t nph hence: */
+       uint16_t i;
+       struct sfdp_tbl_hdr *hdrs;
+       uint8_t *hbuf;
+       uint8_t *tbuf;
+
+       if (spi_sfdp_read_sfdp(flash, 0x00, buf, 4)) {
+               msg_cdbg("Receiving SFDP signature failed.\n");
+               return 0;
+       }
+       tmp32 = buf[0];
+       tmp32 |= ((unsigned int)buf[1]) << 8;
+       tmp32 |= ((unsigned int)buf[2]) << 16;
+       tmp32 |= ((unsigned int)buf[3]) << 24;
+
+       if (tmp32 != 0x50444653) {
+               msg_cdbg2("Signature = 0x%08x (should be 0x50444653)\n", tmp32);
+               msg_cdbg("No SFDP signature found.\n");
+               return 0;
+       }
+
+       if (spi_sfdp_read_sfdp(flash, 0x04, buf, 3)) {
+               msg_cdbg("Receiving SFDP revision and number of parameter "
+                        "headers (NPH) failed. ");
+               return 0;
+       }
+       msg_cdbg2("SFDP revision = %d.%d\n", buf[1], buf[0]);
+       if (buf[1] != 0x01) {
+               msg_cdbg("The chip supports an unknown version of SFDP. "
+                         "Aborting SFDP probe!\n");
+               return 0;
+       }
+       nph = buf[2];
+       msg_cdbg2("SFDP number of parameter headers is %d (NPH = %d).\n",
+                 nph + 1, nph);
+
+       /* Fetch all parameter headers, even if we don't use them all (yet). */
+       hbuf = malloc((nph + 1) * 8);
+       hdrs = malloc((nph + 1) * sizeof(struct sfdp_tbl_hdr));
+       if (hbuf == NULL || hdrs == NULL ) {
+               msg_gerr("Out of memory!\n");
+               goto cleanup_hdrs;
+       }
+       if (spi_sfdp_read_sfdp(flash, 0x08, hbuf, (nph + 1) * 8)) {
+               msg_cdbg("Receiving SFDP parameter table headers failed.\n");
+               goto cleanup_hdrs;
+       }
+
+       for (i = 0; i <= nph; i++) {
+               uint16_t len;
+               hdrs[i].id = hbuf[(8 * i) + 0];
+               hdrs[i].v_minor = hbuf[(8 * i) + 1];
+               hdrs[i].v_major = hbuf[(8 * i) + 2];
+               hdrs[i].len = hbuf[(8 * i) + 3];
+               hdrs[i].ptp = hbuf[(8 * i) + 4];
+               hdrs[i].ptp |= ((unsigned int)hbuf[(8 * i) + 5]) << 8;
+               hdrs[i].ptp |= ((unsigned int)hbuf[(8 * i) + 6]) << 16;
+               msg_cdbg2("\nSFDP parameter table header %d/%d:\n", i, nph);
+               msg_cdbg2("  ID 0x%02x, version %d.%d\n", hdrs[i].id,
+                         hdrs[i].v_major, hdrs[i].v_minor);
+               len = hdrs[i].len * 4;
+               tmp32 = hdrs[i].ptp;
+               msg_cdbg2("  Length %d B, Parameter Table Pointer 0x%06x\n",
+                         len, tmp32);
+
+               if (tmp32 + len >= (1 << 24)) {
+                       msg_cdbg("SFDP Parameter Table %d supposedly overflows "
+                                 "addressable SFDP area. This most\nprobably "
+                                 "indicates a corrupt SFDP parameter table "
+                                 "header. Skipping it.\n", i);
+                       continue;
+               }
+
+               tbuf = malloc(len);
+               if (tbuf == NULL) {
+                       msg_gerr("Out of memory!\n");
+                       goto cleanup_hdrs;
+               }
+               if (spi_sfdp_read_sfdp(flash, tmp32, tbuf, len)){
+                       msg_cdbg("Fetching SFDP parameter table %d failed.\n",
+                                i);
+                       free(tbuf);
+                       continue;
+               }
+               msg_cspew("  Parameter table contents:\n");
+               for (tmp32 = 0; tmp32 < len; tmp32++) {
+                       if ((tmp32 % 8) == 0) {
+                               msg_cspew("    0x%04x: ", tmp32);
+                       }
+                       msg_cspew(" %02x", tbuf[tmp32]);
+                       if ((tmp32 % 8) == 7) {
+                               msg_cspew("\n");
+                               continue;
+                       }
+                       if ((tmp32 % 8) == 3) {
+                               msg_cspew(" ");
+                               continue;
+                       }
+               }
+               msg_cspew("\n");
+
+               if (i == 0) { /* Mandatory JEDEC SFDP parameter table */
+                       if (hdrs[i].id != 0)
+                               msg_cdbg("ID of the mandatory JEDEC SFDP "
+                                        "parameter table is not 0 as demanded "
+                                        "by JESD216 (warning only).\n");
+
+                       if (hdrs[i].v_major != 0x01) {
+                               msg_cdbg("The chip contains an unknown "
+                                         "version of the JEDEC flash "
+                                         "parameters table, skipping it.\n");
+                       } else if (len != 9 * 4 && len != 4 * 4) {
+                               msg_cdbg("Length of the mandatory JEDEC SFDP "
+                                        "parameter table is wrong (%d B), "
+                                        "skipping it.\n", len);
+                       } else if (sfdp_fill_flash(flash, tbuf, len) == 0)
+                               ret = 1;
+               }
+               free(tbuf);
+       }
+
+cleanup_hdrs:
+       free(hdrs);
+       free(hbuf);
+       return ret;
+}
diff --git a/spi.c b/spi.c
new file mode 100644 (file)
index 0000000..62e1430
--- /dev/null
+++ b/spi.c
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 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 generic SPI framework
+ */
+
+#include <strings.h>
+#include <string.h>
+#include "flash.h"
+#include "flashchips.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "spi.h"
+
+int spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                    unsigned int readcnt, const unsigned char *writearr,
+                    unsigned char *readarr)
+{
+       return flash->pgm->spi.command(flash, writecnt, readcnt, writearr,
+                                      readarr);
+}
+
+int spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds)
+{
+       return flash->pgm->spi.multicommand(flash, cmds);
+}
+
+int default_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                            unsigned int readcnt,
+                            const unsigned char *writearr,
+                            unsigned char *readarr)
+{
+       struct spi_command cmd[] = {
+       {
+               .writecnt = writecnt,
+               .readcnt = readcnt,
+               .writearr = writearr,
+               .readarr = readarr,
+       }, {
+               .writecnt = 0,
+               .writearr = NULL,
+               .readcnt = 0,
+               .readarr = NULL,
+       }};
+
+       return spi_send_multicommand(flash, cmd);
+}
+
+int default_spi_send_multicommand(struct flashctx *flash,
+                                 struct spi_command *cmds)
+{
+       int result = 0;
+       for (; (cmds->writecnt || cmds->readcnt) && !result; cmds++) {
+               result = spi_send_command(flash, cmds->writecnt, cmds->readcnt,
+                                         cmds->writearr, cmds->readarr);
+       }
+       return result;
+}
+
+int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
+                    unsigned int len)
+{
+       unsigned int max_data = flash->pgm->spi.max_data_read;
+       if (max_data == MAX_DATA_UNSPECIFIED) {
+               msg_perr("%s called, but SPI read chunk size not defined "
+                        "on this hardware. Please report a bug at "
+                        "flashrom@flashrom.org\n", __func__);
+               return 1;
+       }
+       return spi_read_chunked(flash, buf, start, len, max_data);
+}
+
+int default_spi_write_256(struct flashctx *flash, uint8_t *buf,
+                         unsigned int start, unsigned int len)
+{
+       unsigned int max_data = flash->pgm->spi.max_data_write;
+       if (max_data == MAX_DATA_UNSPECIFIED) {
+               msg_perr("%s called, but SPI write chunk size not defined "
+                        "on this hardware. Please report a bug at "
+                        "flashrom@flashrom.org\n", __func__);
+               return 1;
+       }
+       return spi_write_chunked(flash, buf, start, len, max_data);
+}
+
+int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
+                 unsigned int len)
+{
+       unsigned int addrbase = 0;
+
+       /* Check if the chip fits between lowest valid and highest possible
+        * address. Highest possible address with the current SPI implementation
+        * means 0xffffff, the highest unsigned 24bit number.
+        */
+       addrbase = spi_get_valid_read_addr(flash);
+       if (addrbase + flash->total_size * 1024 > (1 << 24)) {
+               msg_perr("Flash chip size exceeds the allowed access window. ");
+               msg_perr("Read will probably fail.\n");
+               /* Try to get the best alignment subject to constraints. */
+               addrbase = (1 << 24) - flash->total_size * 1024;
+       }
+       /* Check if alignment is native (at least the largest power of two which
+        * is a factor of the mapped size of the chip).
+        */
+       if (ffs(flash->total_size * 1024) > (ffs(addrbase) ? : 33)) {
+               msg_perr("Flash chip is not aligned natively in the allowed "
+                        "access window.\n");
+               msg_perr("Read will probably return garbage.\n");
+       }
+       return flash->pgm->spi.read(flash, buf, addrbase + start, len);
+}
+
+/*
+ * Program chip using page (256 bytes) programming.
+ * Some SPI masters can't do this, they use single byte programming instead.
+ * The redirect to single byte programming is achieved by setting
+ * .write_256 = spi_chip_write_1
+ */
+/* real chunksize is up to 256, logical chunksize is 256 */
+int spi_chip_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start,
+                      unsigned int len)
+{
+       return flash->pgm->spi.write_256(flash, buf, start, len);
+}
+
+/*
+ * Get the lowest allowed address for read accesses. This often happens to
+ * be the lowest allowed address for all commands which take an address.
+ * This is a programmer limitation.
+ */
+uint32_t spi_get_valid_read_addr(struct flashctx *flash)
+{
+       switch (flash->pgm->spi.type) {
+#if CONFIG_INTERNAL == 1
+#if defined(__i386__) || defined(__x86_64__)
+       case SPI_CONTROLLER_ICH7:
+               /* Return BBAR for ICH chipsets. */
+               return ichspi_bbar;
+#endif
+#endif
+       default:
+               return 0;
+       }
+}
+
+int spi_aai_write(struct flashctx *flash, uint8_t *buf,
+                 unsigned int start, unsigned int len)
+{
+       return flash->pgm->spi.write_aai(flash, buf, start, len);
+}
+
+int register_spi_programmer(const struct spi_programmer *pgm)
+{
+       struct registered_programmer rpgm;
+
+       if (!pgm->write_aai || !pgm->write_256 || !pgm->read || !pgm->command ||
+           !pgm->multicommand ||
+           ((pgm->command == default_spi_send_command) &&
+            (pgm->multicommand == default_spi_send_multicommand))) {
+               msg_perr("%s called with incomplete programmer definition. "
+                        "Please report a bug at flashrom@flashrom.org\n",
+                        __func__);
+               return ERROR_FLASHROM_BUG;
+       }
+
+
+       rpgm.buses_supported = BUS_SPI;
+       rpgm.spi = *pgm;
+       return register_programmer(&rpgm);
+}
diff --git a/spi.h b/spi.h
new file mode 100644 (file)
index 0000000..a57f1b6
--- /dev/null
+++ b/spi.h
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008 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
+ */
+
+#ifndef __SPI_H__
+#define __SPI_H__ 1
+
+/*
+ * Contains the generic SPI headers
+ */
+
+/* Read Electronic ID */
+#define JEDEC_RDID             0x9f
+#define JEDEC_RDID_OUTSIZE     0x01
+/* INSIZE may be 0x04 for some chips*/
+#define JEDEC_RDID_INSIZE      0x03
+
+/* AT25F512A has bit 3 as don't care bit in commands */
+#define AT25F512A_RDID         0x15    /* 0x15 or 0x1d */
+#define AT25F512A_RDID_OUTSIZE 0x01
+#define AT25F512A_RDID_INSIZE  0x02
+
+/* Read Electronic Manufacturer Signature */
+#define JEDEC_REMS             0x90
+#define JEDEC_REMS_OUTSIZE     0x04
+#define JEDEC_REMS_INSIZE      0x02
+
+/* Read Serial Flash Discoverable Parameters (SFDP) */
+#define JEDEC_SFDP             0x5a
+#define JEDEC_SFDP_OUTSIZE     0x05    /* 8b op, 24b addr, 8b dummy */
+/*      JEDEC_SFDP_INSIZE : any length */
+
+/* Read Electronic Signature */
+#define JEDEC_RES              0xab
+#define JEDEC_RES_OUTSIZE      0x04
+/* INSIZE may be 0x02 for some chips*/
+#define JEDEC_RES_INSIZE       0x01
+
+/* Write Enable */
+#define JEDEC_WREN             0x06
+#define JEDEC_WREN_OUTSIZE     0x01
+#define JEDEC_WREN_INSIZE      0x00
+
+/* Write Disable */
+#define JEDEC_WRDI             0x04
+#define JEDEC_WRDI_OUTSIZE     0x01
+#define JEDEC_WRDI_INSIZE      0x00
+
+/* Chip Erase 0x60 is supported by Macronix/SST chips. */
+#define JEDEC_CE_60            0x60
+#define JEDEC_CE_60_OUTSIZE    0x01
+#define JEDEC_CE_60_INSIZE     0x00
+
+/* Chip Erase 0xc7 is supported by SST/ST/EON/Macronix chips. */
+#define JEDEC_CE_C7            0xc7
+#define JEDEC_CE_C7_OUTSIZE    0x01
+#define JEDEC_CE_C7_INSIZE     0x00
+
+/* Block Erase 0x52 is supported by SST and old Atmel chips. */
+#define JEDEC_BE_52            0x52
+#define JEDEC_BE_52_OUTSIZE    0x04
+#define JEDEC_BE_52_INSIZE     0x00
+
+/* Block Erase 0xd8 is supported by EON/Macronix chips. */
+#define JEDEC_BE_D8            0xd8
+#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
+#define JEDEC_SE_INSIZE                0x00
+
+/* Read Status Register */
+#define JEDEC_RDSR             0x05
+#define JEDEC_RDSR_OUTSIZE     0x01
+#define JEDEC_RDSR_INSIZE      0x01
+
+/* Status Register Bits */
+#define SPI_SR_WIP     (0x01 << 0)
+#define SPI_SR_WEL     (0x01 << 1)
+#define SPI_SR_AAI     (0x01 << 6)
+
+/* Write Status Enable */
+#define JEDEC_EWSR             0x50
+#define JEDEC_EWSR_OUTSIZE     0x01
+#define JEDEC_EWSR_INSIZE      0x00
+
+/* Write Status Register */
+#define JEDEC_WRSR             0x01
+#define JEDEC_WRSR_OUTSIZE     0x02
+#define JEDEC_WRSR_INSIZE      0x00
+
+/* Read the memory */
+#define JEDEC_READ             0x03
+#define JEDEC_READ_OUTSIZE     0x04
+/*      JEDEC_READ_INSIZE : any length */
+
+/* Write memory byte */
+#define JEDEC_BYTE_PROGRAM             0x02
+#define JEDEC_BYTE_PROGRAM_OUTSIZE     0x05
+#define JEDEC_BYTE_PROGRAM_INSIZE      0x00
+
+/* Write AAI word (SST25VF080B) */
+#define JEDEC_AAI_WORD_PROGRAM                 0xad
+#define JEDEC_AAI_WORD_PROGRAM_OUTSIZE         0x06
+#define JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE    0x03
+#define JEDEC_AAI_WORD_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
+#define SPI_FLASHROM_BUG       -5
+#define SPI_PROGRAMMER_ERROR   -6
+
+#endif         /* !__SPI_H__ */
diff --git a/spi25.c b/spi25.c
new file mode 100644 (file)
index 0000000..900df9c
--- /dev/null
+++ b/spi25.c
@@ -0,0 +1,1192 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007, 2008, 2009, 2010 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 <string.h>
+#include "flash.h"
+#include "flashchips.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "spi.h"
+
+static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
+{
+       static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
+       int ret;
+       int i;
+
+       ret = spi_send_command(flash, 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(struct flashctx *flash, unsigned char *readarr)
+{
+       unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 };
+       uint32_t readaddr;
+       int ret;
+
+       ret = spi_send_command(flash, 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(flash) + 1) & ~1;
+               cmd[1] = (readaddr >> 16) & 0xff,
+               cmd[2] = (readaddr >> 8) & 0xff,
+               cmd[3] = (readaddr >> 0) & 0xff,
+               ret = spi_send_command(flash, sizeof(cmd), JEDEC_REMS_INSIZE,
+                                      cmd, readarr);
+       }
+       if (ret)
+               return ret;
+       msg_cspew("REMS returned 0x%02x 0x%02x. ", readarr[0], readarr[1]);
+       return 0;
+}
+
+static int spi_res(struct flashctx *flash, unsigned char *readarr, int bytes)
+{
+       unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 };
+       uint32_t readaddr;
+       int ret;
+       int i;
+
+       ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
+       if (ret == SPI_INVALID_ADDRESS) {
+               /* Find the lowest even address allowed for reads. */
+               readaddr = (spi_get_valid_read_addr(flash) + 1) & ~1;
+               cmd[1] = (readaddr >> 16) & 0xff,
+               cmd[2] = (readaddr >> 8) & 0xff,
+               cmd[3] = (readaddr >> 0) & 0xff,
+               ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
+       }
+       if (ret)
+               return ret;
+       msg_cspew("RES returned");
+       for (i = 0; i < bytes; i++)
+               msg_cspew(" 0x%02x", readarr[i]);
+       msg_cspew(". ");
+       return 0;
+}
+
+int spi_write_enable(struct flashctx *flash)
+{
+       static const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
+       int result;
+
+       /* Send WREN (Write Enable) */
+       result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+
+       if (result)
+               msg_cerr("%s failed\n", __func__);
+
+       return result;
+}
+
+int spi_write_disable(struct flashctx *flash)
+{
+       static const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI };
+
+       /* Send WRDI (Write Disable) */
+       return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+}
+
+static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
+{
+       unsigned char readarr[4];
+       uint32_t id1;
+       uint32_t id2;
+
+       if (spi_rdid(flash, readarr, bytes)) {
+               return 0;
+       }
+
+       if (!oddparity(readarr[0]))
+               msg_cdbg("RDID byte 0 parity violation. ");
+
+       /* Check if this is a continuation vendor ID.
+        * FIXME: Handle continuation device IDs.
+        */
+       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 flashctx *flash)
+{
+       return probe_spi_rdid_generic(flash, 3);
+}
+
+int probe_spi_rdid4(struct flashctx *flash)
+{
+       /* Some SPI controllers do not support commands with writecnt=1 and
+        * readcnt=4.
+        */
+       switch (flash->pgm->spi.type) {
+#if CONFIG_INTERNAL == 1
+#if defined(__i386__) || defined(__x86_64__)
+       case SPI_CONTROLLER_IT87XX:
+       case SPI_CONTROLLER_WBSIO:
+               msg_cinfo("4 byte RDID not supported on this SPI controller\n");
+               return 0;
+               break;
+#endif
+#endif
+       default:
+               return probe_spi_rdid_generic(flash, 4);
+       }
+
+       return 0;
+}
+
+int probe_spi_rems(struct flashctx *flash)
+{
+       unsigned char readarr[JEDEC_REMS_INSIZE];
+       uint32_t id1, id2;
+
+       if (spi_rems(flash, 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_res1(struct flashctx *flash)
+{
+       static const unsigned char allff[] = {0xff, 0xff, 0xff};
+       static const unsigned char all00[] = {0x00, 0x00, 0x00};
+       unsigned char readarr[3];
+       uint32_t id2;
+
+       /* We only want one-byte RES if RDID and REMS are unusable. */
+
+       /* 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(flash, 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(flash, 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(flash, readarr, 1)) {
+               return 0;
+       }
+
+       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;
+}
+
+int probe_spi_res2(struct flashctx *flash)
+{
+       unsigned char readarr[2];
+       uint32_t id1, id2;
+
+       if (spi_res(flash, readarr, 2)) {
+               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)
+               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(struct flashctx *flash)
+{
+       static 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(flash, 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_welwip(uint8_t status)
+{
+       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. Common definitions. */
+void spi_prettyprint_status_register_bp(uint8_t status, int bp)
+{
+       switch (bp) {
+       /* Fall through. */
+       case 4:
+               msg_cdbg("Chip status register: Block Protect 4 (BP4) "
+                            "is %sset\n", (status & (1 << 5)) ? "" : "not ");
+       case 3:
+               msg_cdbg("Chip status register: Block Protect 3 (BP3) "
+                            "is %sset\n", (status & (1 << 5)) ? "" : "not ");
+       case 2:
+               msg_cdbg("Chip status register: Block Protect 2 (BP2) "
+                            "is %sset\n", (status & (1 << 4)) ? "" : "not ");
+       case 1:
+               msg_cdbg("Chip status register: Block Protect 1 (BP1) "
+                            "is %sset\n", (status & (1 << 3)) ? "" : "not ");
+       case 0:
+               msg_cdbg("Chip status register: Block Protect 0 (BP0) "
+                            "is %sset\n", (status & (1 << 2)) ? "" : "not ");
+       }
+}
+
+/* Prettyprint the status register. Unnamed bits. */
+void spi_prettyprint_status_register_bit(uint8_t status, int bit)
+{
+       msg_cdbg("Chip status register: Bit %i "
+                "is %sset\n", bit, (status & (1 << bit)) ? "" : "not ");
+}
+
+static void spi_prettyprint_status_register_common(uint8_t status)
+{
+       spi_prettyprint_status_register_bp(status, 3);
+       spi_prettyprint_status_register_welwip(status);
+}
+
+/* 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)
+{
+       static const char *const 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)
+{
+       static const char *const 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]);
+}
+
+int spi_prettyprint_status_register(struct flashctx *flash)
+{
+       uint8_t status;
+
+       status = spi_read_status_register(flash);
+       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 MACRONIX_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;
+       }
+       return 0;
+}
+
+int spi_chip_erase_60(struct flashctx *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_send_multicommand(flash, 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(flash) & SPI_SR_WIP)
+               programmer_delay(1000 * 1000);
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int spi_chip_erase_c7(struct flashctx *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_send_multicommand(flash, 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(flash) & SPI_SR_WIP)
+               programmer_delay(1000 * 1000);
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int spi_block_erase_52(struct flashctx *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(flash, 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(flash) & SPI_SR_WIP)
+               programmer_delay(100 * 1000);
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+/* Block size is usually
+ * 64k for Macronix
+ * 32k for SST
+ * 4-32k non-uniform for EON
+ */
+int spi_block_erase_d8(struct flashctx *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(flash, 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(flash) & SPI_SR_WIP)
+               programmer_delay(100 * 1000);
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+/* Block size is usually
+ * 4k for PMC
+ */
+int spi_block_erase_d7(struct flashctx *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(flash, 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(flash) & SPI_SR_WIP)
+               programmer_delay(100 * 1000);
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+/* Sector size is usually 4k, though Macronix eliteflash has 64k */
+int spi_block_erase_20(struct flashctx *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(flash, 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(flash) & SPI_SR_WIP)
+               programmer_delay(10 * 1000);
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int spi_block_erase_60(struct flashctx *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 flashctx *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);
+}
+
+erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode)
+{
+       switch(opcode){
+       case 0xff:
+       case 0x00:
+               /* Not specified, assuming "not supported". */
+               return NULL;
+       case 0x20:
+               return &spi_block_erase_20;
+       case 0x52:
+               return &spi_block_erase_52;
+       case 0x60:
+               return &spi_block_erase_60;
+       case 0xc7:
+               return &spi_block_erase_c7;
+       case 0xd7:
+               return &spi_block_erase_d7;
+       case 0xd8:
+               return &spi_block_erase_d8;
+       default:
+               msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
+                         "this at flashrom@flashrom.org\n", __func__, opcode);
+               return NULL;
+       }
+}
+
+int spi_write_status_enable(struct flashctx *flash)
+{
+       static const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR };
+       int result;
+
+       /* Send EWSR (Enable Write Status Register). */
+       result = spi_send_command(flash, 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...
+ */
+static int spi_write_status_register_flag(struct flashctx *flash, int status, const unsigned char enable_opcode)
+{
+       int result;
+       int i = 0;
+       /*
+        * WRSR requires either EWSR or WREN depending on chip type.
+        * The code below relies on the fact hat EWSR and WREN have the same
+        * INSIZE and OUTSIZE.
+        */
+       struct spi_command cmds[] = {
+       {
+               .writecnt       = JEDEC_WREN_OUTSIZE,
+               .writearr       = (const unsigned char[]){ enable_opcode },
+               .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(flash, cmds);
+       if (result) {
+               msg_cerr("%s failed during command execution\n", __func__);
+               /* No point in waiting for the command to complete if execution
+                * failed.
+                */
+               return result;
+       }
+       /* WRSR performs a self-timed erase before the changes take effect.
+        * This may take 50-85 ms in most cases, and some chips apparently
+        * allow running RDSR only once. Therefore pick an initial delay of
+        * 100 ms, then wait in 10 ms steps until a total of 5 s have elapsed.
+        */
+       programmer_delay(100 * 1000);
+       while (spi_read_status_register(flash) & SPI_SR_WIP) {
+               if (++i > 490) {
+                       msg_cerr("Error: WIP bit after WRSR never cleared\n");
+                       return TIMEOUT_ERROR;
+               }
+               programmer_delay(10 * 1000);
+       }
+       return 0;
+}
+
+int spi_write_status_register(struct flashctx *flash, int status)
+{
+       int feature_bits = flash->feature_bits;
+       int ret = 1;
+
+       if (!(feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
+               msg_cdbg("Missing status register write definition, assuming "
+                        "EWSR is needed\n");
+               feature_bits |= FEATURE_WRSR_EWSR;
+       }
+       if (feature_bits & FEATURE_WRSR_WREN)
+               ret = spi_write_status_register_flag(flash, status, JEDEC_WREN);
+       if (ret && (feature_bits & FEATURE_WRSR_EWSR))
+               ret = spi_write_status_register_flag(flash, status, JEDEC_EWSR);
+       return ret;
+}
+
+int spi_byte_program(struct flashctx *flash, unsigned 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(flash, cmds);
+       if (result) {
+               msg_cerr("%s failed during command execution at address 0x%x\n",
+                       __func__, addr);
+       }
+       return result;
+}
+
+int spi_nbyte_program(struct flashctx *flash, unsigned int addr, uint8_t *bytes,
+                     unsigned 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(flash, cmds);
+       if (result) {
+               msg_cerr("%s failed during command execution at address 0x%x\n",
+                       __func__, addr);
+       }
+       return result;
+}
+
+/* A generic brute-force block protection disable works like this:
+ * Write 0x00 to the status register. Check if any locks are still set (that
+ * part is chip specific). Repeat once.
+ */
+int spi_disable_blockprotect(struct flashctx *flash)
+{
+       uint8_t status;
+       int result;
+
+       status = spi_read_status_register(flash);
+       /* If block protection is disabled, stop here. */
+       if ((status & 0x3c) == 0)
+               return 0;
+
+       msg_cdbg("Some block protection in effect, disabling... ");
+       result = spi_write_status_register(flash, status & ~0x3c);
+       if (result) {
+               msg_cerr("spi_write_status_register failed.\n");
+               return result;
+       }
+       status = spi_read_status_register(flash);
+       if ((status & 0x3c) != 0) {
+               msg_cerr("Block protection could not be disabled!\n");
+               return 1;
+       }
+       msg_cdbg("done.\n");
+       return 0;
+}
+
+int spi_nbyte_read(struct flashctx *flash, unsigned int address, uint8_t *bytes,
+                  unsigned 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(flash, sizeof(cmd), len, cmd, bytes);
+}
+
+/*
+ * Read a part of the flash chip.
+ * FIXME: Use the chunk code from Michael Karcher instead.
+ * Each page is read separately in chunks with a maximum size of chunksize.
+ */
+int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
+                    unsigned int len, unsigned int chunksize)
+{
+       int rc = 0;
+       unsigned int i, j, starthere, lenhere, toread;
+       unsigned int page_size = flash->page_size;
+
+       /* 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(flash, starthere + j, buf + starthere - start + j, toread);
+                       if (rc)
+                               break;
+               }
+               if (rc)
+                       break;
+       }
+
+       return rc;
+}
+
+/*
+ * Write a part of the flash chip.
+ * FIXME: Use the chunk code from Michael Karcher instead.
+ * Each page is written separately in chunks with a maximum size of chunksize.
+ */
+int spi_write_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
+                     unsigned int len, unsigned int chunksize)
+{
+       int rc = 0;
+       unsigned int i, j, starthere, lenhere, towrite;
+       /* FIXME: page_size is the wrong variable. We need max_writechunk_size
+        * in struct flashctx to do this properly. All chips using
+        * spi_chip_write_256 have page_size set to max_writechunk_size, so
+        * we're OK for now.
+        */
+       unsigned int page_size = flash->page_size;
+
+       /* 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) {
+                       towrite = min(chunksize, lenhere - j);
+                       rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
+                       if (rc)
+                               break;
+                       while (spi_read_status_register(flash) & SPI_SR_WIP)
+                               programmer_delay(10);
+               }
+               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)
+ */
+/* real chunksize is 1, logical chunksize is 1 */
+int spi_chip_write_1(struct flashctx *flash, uint8_t *buf, unsigned int start,
+                    unsigned int len)
+{
+       unsigned int i;
+       int result = 0;
+
+       for (i = start; i < start + len; i++) {
+               result = spi_byte_program(flash, i, buf[i - start]);
+               if (result)
+                       return 1;
+               while (spi_read_status_register(flash) & SPI_SR_WIP)
+                       programmer_delay(10);
+       }
+
+       return 0;
+}
+
+int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+       uint32_t pos = start;
+       int result;
+       unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
+               JEDEC_AAI_WORD_PROGRAM,
+       };
+       struct spi_command cmds[] = {
+       {
+               .writecnt       = JEDEC_WREN_OUTSIZE,
+               .writearr       = (const unsigned char[]){ JEDEC_WREN },
+               .readcnt        = 0,
+               .readarr        = NULL,
+       }, {
+               .writecnt       = JEDEC_AAI_WORD_PROGRAM_OUTSIZE,
+               .writearr       = (const unsigned char[]){
+                                       JEDEC_AAI_WORD_PROGRAM,
+                                       (start >> 16) & 0xff,
+                                       (start >> 8) & 0xff,
+                                       (start & 0xff),
+                                       buf[0],
+                                       buf[1]
+                               },
+               .readcnt        = 0,
+               .readarr        = NULL,
+       }, {
+               .writecnt       = 0,
+               .writearr       = NULL,
+               .readcnt        = 0,
+               .readarr        = NULL,
+       }};
+
+       switch (flash->pgm->spi.type) {
+#if CONFIG_INTERNAL == 1
+#if defined(__i386__) || defined(__x86_64__)
+       case SPI_CONTROLLER_IT87XX:
+       case SPI_CONTROLLER_WBSIO:
+               msg_perr("%s: impossible with this SPI controller,"
+                               " degrading to byte program\n", __func__);
+               return spi_chip_write_1(flash, buf, start, len);
+#endif
+#endif
+       default:
+               break;
+       }
+
+       /* The even start address and even length requirements can be either
+        * honored outside this function, or we can call spi_byte_program
+        * for the first and/or last byte and use AAI for the rest.
+        * FIXME: Move this to generic code.
+        */
+       /* The data sheet requires a start address with the low bit cleared. */
+       if (start % 2) {
+               msg_cerr("%s: start address not even! Please report a bug at "
+                        "flashrom@flashrom.org\n", __func__);
+               if (spi_chip_write_1(flash, buf, start, start % 2))
+                       return SPI_GENERIC_ERROR;
+               pos += start % 2;
+               cmds[1].writearr = (const unsigned char[]){
+                                       JEDEC_AAI_WORD_PROGRAM,
+                                       (pos >> 16) & 0xff,
+                                       (pos >> 8) & 0xff,
+                                       (pos & 0xff),
+                                       buf[pos - start],
+                                       buf[pos - start + 1]
+                               };
+               /* Do not return an error for now. */
+               //return SPI_GENERIC_ERROR;
+       }
+       /* The data sheet requires total AAI write length to be even. */
+       if (len % 2) {
+               msg_cerr("%s: total write length not even! Please report a "
+                        "bug at flashrom@flashrom.org\n", __func__);
+               /* Do not return an error for now. */
+               //return SPI_GENERIC_ERROR;
+       }
+
+
+       result = spi_send_multicommand(flash, cmds);
+       if (result) {
+               msg_cerr("%s failed during start command execution\n",
+                        __func__);
+               /* FIXME: Should we send WRDI here as well to make sure the chip
+                * is not in AAI mode?
+                */
+               return result;
+       }
+       while (spi_read_status_register(flash) & SPI_SR_WIP)
+               programmer_delay(10);
+
+       /* We already wrote 2 bytes in the multicommand step. */
+       pos += 2;
+
+       /* Are there at least two more bytes to write? */
+       while (pos < start + len - 1) {
+               cmd[1] = buf[pos++ - start];
+               cmd[2] = buf[pos++ - start];
+               spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0,
+                                cmd, NULL);
+               while (spi_read_status_register(flash) & SPI_SR_WIP)
+                       programmer_delay(10);
+       }
+
+       /* Use WRDI to exit AAI mode. This needs to be done before issuing any
+        * other non-AAI command.
+        */
+       spi_write_disable(flash);
+
+       /* Write remaining byte (if any). */
+       if (pos < start + len) {
+               if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2))
+                       return SPI_GENERIC_ERROR;
+               pos += pos % 2;
+       }
+
+       return 0;
+}
diff --git a/sst28sf040.c b/sst28sf040.c
new file mode 100644 (file)
index 0000000..a9a740c
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2005 coresystems GmbH <stepan@openbios.org>
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+#include "chipdrivers.h"
+
+#define AUTO_PG_ERASE1         0x20
+#define AUTO_PG_ERASE2         0xD0
+#define AUTO_PGRM              0x10
+#define CHIP_ERASE             0x30
+#define RESET                  0xFF
+#define READ_ID                        0x90
+
+int protect_28sf040(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+
+       chip_readb(flash, bios + 0x1823);
+       chip_readb(flash, bios + 0x1820);
+       chip_readb(flash, bios + 0x1822);
+       chip_readb(flash, bios + 0x0418);
+       chip_readb(flash, bios + 0x041B);
+       chip_readb(flash, bios + 0x0419);
+       chip_readb(flash, bios + 0x040A);
+
+       return 0;
+}
+
+int unprotect_28sf040(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+
+       chip_readb(flash, bios + 0x1823);
+       chip_readb(flash, bios + 0x1820);
+       chip_readb(flash, bios + 0x1822);
+       chip_readb(flash, bios + 0x0418);
+       chip_readb(flash, bios + 0x041B);
+       chip_readb(flash, bios + 0x0419);
+       chip_readb(flash, bios + 0x041A);
+
+       return 0;
+}
+
+int erase_sector_28sf040(struct flashctx *flash, unsigned int address,
+                        unsigned int sector_size)
+{
+       chipaddr bios = flash->virtual_memory;
+
+       /* This command sequence is very similar to erase_block_82802ab. */
+       chip_writeb(flash, AUTO_PG_ERASE1, bios);
+       chip_writeb(flash, AUTO_PG_ERASE2, bios + address);
+
+       /* wait for Toggle bit ready */
+       toggle_ready_jedec(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+/* chunksize is 1 */
+int write_28sf040(struct flashctx *flash, uint8_t *src, unsigned int start,
+                 unsigned int len)
+{
+       int i;
+       chipaddr bios = flash->virtual_memory;
+       chipaddr dst = flash->virtual_memory + start;
+
+       for (i = 0; i < len; 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(flash, AUTO_PGRM, dst);
+               chip_writeb(flash, *src++, dst++);
+
+               /* wait for Toggle bit ready */
+               toggle_ready_jedec(flash, bios);
+       }
+
+       return 0;
+}
+
+static int erase_28sf040(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+
+       chip_writeb(flash, CHIP_ERASE, bios);
+       chip_writeb(flash, CHIP_ERASE, bios);
+
+       programmer_delay(10);
+       toggle_ready_jedec(flash, bios);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
+
+int erase_chip_28sf040(struct flashctx *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/sst49lfxxxc.c b/sst49lfxxxc.c
new file mode 100644 (file)
index 0000000..37f0628
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2005-2007 coresystems GmbH
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "flash.h"
+#include "chipdrivers.h"
+
+static int write_lockbits_block_49lfxxxc(struct flashctx *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(flash, lock));
+       chip_writeb(flash, bits, lock);
+
+       return 0;
+}
+
+static int write_lockbits_49lfxxxc(struct flashctx *flash, unsigned char bits)
+{
+       chipaddr registers = flash->virtual_registers;
+       unsigned int i, left = flash->total_size * 1024;
+       unsigned long address;
+
+       msg_cdbg("\nbios=0x%08lx\n", registers);
+       for (i = 0; left > 65536; i++, left -= 65536) {
+               write_lockbits_block_49lfxxxc(flash, i * 65536, bits);
+       }
+       address = i * 65536;
+       write_lockbits_block_49lfxxxc(flash, address, bits);
+       address += 32768;
+       write_lockbits_block_49lfxxxc(flash, address, bits);
+       address += 8192;
+       write_lockbits_block_49lfxxxc(flash, address, bits);
+       address += 8192;
+       write_lockbits_block_49lfxxxc(flash, address, bits);
+
+       return 0;
+}
+
+int unlock_49lfxxxc(struct flashctx *flash)
+{
+       return write_lockbits_49lfxxxc(flash, 0);
+}
+
+int erase_sector_49lfxxxc(struct flashctx *flash, unsigned int address,
+                         unsigned int sector_size)
+{
+       uint8_t status;
+       chipaddr bios = flash->virtual_memory;
+
+       chip_writeb(flash, 0x30, bios);
+       chip_writeb(flash, 0xD0, bios + address);
+
+       status = wait_82802ab(flash);
+       print_status_82802ab(status);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
diff --git a/sst_fwhub.c b/sst_fwhub.c
new file mode 100644 (file)
index 0000000..c802a33
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 <audiohacked@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Adapted from the Intel FW hub stuff for 82802ax parts. */
+
+#include "flash.h"
+
+static int check_sst_fwhub_block_lock(struct flashctx *flash, int offset)
+{
+       chipaddr registers = flash->virtual_registers;
+       uint8_t blockstatus;
+
+       blockstatus = chip_readb(flash, registers + offset + 2);
+       msg_cdbg("Lock status for 0x%06x (size 0x%06x) is %02x, ",
+                    offset, flash->page_size, blockstatus);
+       switch (blockstatus & 0x3) {
+       case 0x0:
+               msg_cdbg("full access\n");
+               break;
+       case 0x1:
+               msg_cdbg("write locked\n");
+               break;
+       case 0x2:
+               msg_cdbg("locked open\n");
+               break;
+       case 0x3:
+               msg_cdbg("write locked down\n");
+               break;
+       }
+       /* Return content of the write_locked bit */
+       return blockstatus & 0x1;
+}
+
+static int clear_sst_fwhub_block_lock(struct flashctx *flash, int offset)
+{
+       chipaddr registers = flash->virtual_registers;
+       uint8_t blockstatus;
+
+       blockstatus = check_sst_fwhub_block_lock(flash, offset);
+
+       if (blockstatus) {
+               msg_cdbg("Trying to clear lock for 0x%06x... ", offset);
+               chip_writeb(flash, 0, registers + offset + 2);
+
+               blockstatus = check_sst_fwhub_block_lock(flash, offset);
+               msg_cdbg("%s\n", (blockstatus) ? "failed" : "OK");
+       }
+
+       return blockstatus;
+}
+
+int printlock_sst_fwhub(struct flashctx *flash)
+{
+       int i;
+
+       for (i = 0; i < flash->total_size * 1024; i += flash->page_size)
+               check_sst_fwhub_block_lock(flash, i);
+
+       return 0;
+}
+
+int unlock_sst_fwhub(struct flashctx *flash)
+{
+       int i, ret=0;
+
+       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 ret;
+}
+
diff --git a/stm50flw0x0x.c b/stm50flw0x0x.c
new file mode 100644 (file)
index 0000000..9b6443e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.com>
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * This module is designed for supporting the devices
+ * ST M50FLW040A (not yet tested)
+ * ST M50FLW040B (not yet tested)
+ * ST M50FLW080A
+ * ST M50FLW080B (not yet tested)
+ */
+
+#include "flash.h"
+#include "flashchips.h"
+#include "chipdrivers.h"
+
+/*
+ * claus.gindhart@kontron.com
+ * The ST M50FLW080B and STM50FLW080B chips have to be unlocked,
+ * before you can erase them or write to them.
+ */
+static int unlock_block_stm50flw0x0x(struct flashctx *flash, int offset)
+{
+       chipaddr wrprotect = flash->virtual_registers + 2;
+       static const uint8_t unlock_sector = 0x00;
+       int j;
+
+       /*
+        * These chips have to be unlocked before you can erase them or write
+        * to them. The size of the locking sectors depends on the type
+        * of chip.
+        *
+        * Sometimes, the BIOS does this for you; so you probably
+        * don't need to worry about that.
+        */
+
+       /* Check, if it's is a top/bottom-block with 4k-sectors. */
+       /* TODO: What about the other types? */
+       if ((offset == 0) ||
+           (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000))
+           || (offset == 0xF0000)) {
+
+               // unlock each 4k-sector
+               for (j = 0; j < 0x10000; j += 0x1000) {
+                       msg_cdbg("unlocking at 0x%x\n", offset + j);
+                       chip_writeb(flash, unlock_sector,
+                                   wrprotect + offset + j);
+                       if (chip_readb(flash, wrprotect + offset + j) !=
+                           unlock_sector) {
+                               msg_cerr("Cannot unlock sector @ 0x%x\n",
+                                      offset + j);
+                               return -1;
+                       }
+               }
+       } else {
+               msg_cdbg("unlocking at 0x%x\n", offset);
+               chip_writeb(flash, unlock_sector, wrprotect + offset);
+               if (chip_readb(flash, wrprotect + offset) != unlock_sector) {
+                       msg_cerr("Cannot unlock sector @ 0x%x\n", offset);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int unlock_stm50flw0x0x(struct flashctx *flash)
+{
+       int i;
+
+       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;
+               }
+       }
+
+       return 0;
+}
+
+/* This function is unused. */
+int erase_sector_stm50flw0x0x(struct flashctx *flash, unsigned int sector,
+                             unsigned int sectorsize)
+{
+       chipaddr bios = flash->virtual_memory + sector;
+
+       // clear status register
+       chip_writeb(flash, 0x50, bios);
+       // now start it
+       chip_writeb(flash, 0x32, bios);
+       chip_writeb(flash, 0xd0, bios);
+       programmer_delay(10);
+
+       wait_82802ab(flash);
+
+       /* FIXME: Check the status register for errors. */
+       return 0;
+}
diff --git a/udelay.c b/udelay.c
new file mode 100644 (file)
index 0000000..5faa004
--- /dev/null
+++ b/udelay.c
@@ -0,0 +1,196 @@
+/*
+ * 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
+ * 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
+ */
+
+#ifndef __LIBPAYLOAD__
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "flash.h"
+
+/* loops per microsecond */
+static unsigned long micro = 1;
+
+__attribute__ ((noinline)) void myusec_delay(int usecs)
+{
+       unsigned long i;
+       for (i = 0; i < usecs * micro; i++) {
+               /* Make sure the compiler doesn't optimize the loop away. */
+               asm volatile ("" : : "rm" (i) );
+       }
+}
+
+static unsigned long measure_os_delay_resolution(void)
+{
+       unsigned long timeusec;
+       struct timeval start, end;
+       unsigned long counter = 0;
+       
+       gettimeofday(&start, NULL);
+       timeusec = 0;
+       
+       while (!timeusec && (++counter < 1000000000)) {
+               gettimeofday(&end, NULL);
+               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 = 0;
+               /* Protect against time going backwards during leap seconds. */
+               if ((end.tv_sec < start.tv_sec) || (timeusec > LONG_MAX))
+                       timeusec = 0;
+       }
+       return timeusec;
+}
+
+static unsigned long measure_delay(int usecs)
+{
+       unsigned long timeusec;
+       struct timeval start, end;
+       
+       gettimeofday(&start, NULL);
+       myusec_delay(usecs);
+       gettimeofday(&end, NULL);
+       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, resolution;
+       int i, tries = 0;
+
+       msg_pinfo("Calibrating delay loop... ");
+       resolution = measure_os_delay_resolution();
+       if (resolution) {
+               msg_pdbg("OS timer resolution is %lu usecs, ", resolution);
+       } else {
+               msg_pinfo("OS timer resolution is unusable. ");
+       }
+
+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;
+       }
+       tries ++;
+
+       /* 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 (resolution && (resolution < 10)) {
+                               timeusec = measure_delay(100);
+                       } else if (resolution && 
+                                  (resolution < ULONG_MAX / 200)) {
+                               timeusec = measure_delay(resolution * 10) *
+                                          100 / (resolution * 10);
+                       } else {
+                               /* This workaround should be active for broken
+                                * OS and maybe libpayload. The criterion
+                                * here is horrible or non-measurable OS timer
+                                * resolution which will result in
+                                * measure_delay(100)=0 whereas a longer delay
+                                * (1000 ms) may be sufficient
+                                * to get a nonzero time measurement.
+                                */
+                               timeusec = measure_delay(1000000) / 10000;
+                       }
+                       if (timeusec < 90) {
+                               msg_pdbg("delay more than 10%% too short (got "
+                                        "%lu%% of expected delay), "
+                                        "recalculating... ", timeusec);
+                               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);
+       timeusec = measure_delay(resolution * 4);
+       msg_pdbg("%ld myus = %ld us, ", resolution * 4, timeusec);
+
+       msg_pinfo("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);
+       }
+}
+
+#else 
+#include <libpayload.h>
+
+void myusec_calibrate_delay(void)
+{
+       get_cpu_speed();
+}
+
+void internal_delay(int usecs)
+{
+       udelay(usecs);
+}
+#endif
diff --git a/util/flashrom_partial_write_test.sh b/util/flashrom_partial_write_test.sh
new file mode 100755 (executable)
index 0000000..2d83752
--- /dev/null
@@ -0,0 +1,293 @@
+#!/bin/sh
+#
+# Copyright (C) 2010 Google Inc.
+# Written by David Hendricks for Google Inc.
+#
+# 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
+#
+# This script attempts to test Flashrom partial write capability by writing
+# patterns of 0xff and 0x00 bytes to the lowest 128kB of flash. 128kB is chosen
+# since 64kB is usually the largest possible block size, so we will try to
+# cover at least two blocks with this test.
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+# The copy of flashrom to test. If unset, we'll assume the user wants to test
+# a newly built flashrom binary in the parent directory (this script should
+# reside in flashrom/util).
+if [ -z "$FLASHROM" ] ; then
+       FLASHROM="../flashrom"
+fi
+echo "testing flashrom binary: ${FLASHROM}"
+
+OLDDIR=$(pwd)
+
+# test data location
+TMPDIR=$(mktemp -d -t flashrom_test.XXXXXXXXXX)
+if [ "$?" != "0" ] ; then
+       echo "Could not create temporary directory"
+       exit $EXIT_FAILURE
+fi
+
+ZERO_4K="00_4k.bin"
+FF_4K="ff_4k.bin"
+FF_4K_TEXT="ff_4k.txt"
+
+TESTFILE="test.bin"
+
+which uuencode > /dev/null
+if [ "$?" != "0" ] ; then
+       echo "uuencode is required to use this script"
+       exit $EXIT_FAILURE
+fi
+
+which flashrom > /dev/null
+if [ "$?" != "0" ] ; then
+       echo "Please install a stable version of flashrom in your path."
+       echo "This will be used to compare the test flashrom binary and "
+       echo "restore your firmware image at the end of the test."
+       exit $EXIT_FAILURE
+fi
+
+# Keep a copy of flashrom with the test data
+cp "$FLASHROM" "${TMPDIR}/"
+cd "$TMPDIR"
+echo "Running test in ${TMPDIR}"
+
+# Make 4k worth of 0xff bytes
+echo "begin 640 $FF_4K" > "$FF_4K_TEXT"
+i=0
+while [ $i -le 90 ] ; do
+       echo "M____________________________________________________________" >> "$FF_4K_TEXT"
+       i=$((${i} + 1))
+done
+echo "!_P``" >> "$FF_4K_TEXT"
+echo "\`" >> "$FF_4K_TEXT"
+echo "end" >> "$FF_4K_TEXT"
+uudecode -o "$FF_4K" "$FF_4K_TEXT"
+rm -f "$FF_4K_TEXT"
+
+# Make 4k worth of 0x00 bytes
+dd if=/dev/zero of="$ZERO_4K" bs=1 count=4096 2> /dev/null
+echo "ffh pattern written in ${FF_4K}"
+echo "00h pattern written in ${ZERO_4K}"
+
+echo "Reading BIOS image"
+BIOS="bios.bin"
+flashrom ${FLASHROM_PARAM} -r "$BIOS" > /dev/null
+echo "Original image saved as ${BIOS}"
+
+# $1: exit code
+do_exit() {
+       if [ ${1} -eq ${EXIT_FAILURE} ] ; then
+               echo "Result: FAILED"
+       else
+               echo "Result: PASSED"
+       fi
+
+       echo "restoring original bios image using system's flashrom"
+       flashrom ${FLASHROM_PARAM} -w "$BIOS"
+       echo "test files remain in ${TMPDIR}"
+       cd "$OLDDIR"
+       exit "$1"
+}
+
+#
+# Actual tests are performed below.
+#
+NUM_REGIONS=16
+
+# Make a layout - 4K regions on 4K boundaries. This will test basic
+# functionality of erasing and writing specific blocks.
+echo "
+0x000000:0x000fff 00_0
+0x001000:0x001fff ff_0
+
+0x002000:0x002fff 00_1
+0x003000:0x003fff ff_1
+
+0x004000:0x004fff 00_2
+0x005000:0x005fff ff_2
+
+0x006000:0x006fff 00_3
+0x007000:0x007fff ff_3
+
+0x008000:0x008fff 00_4
+0x009000:0x009fff ff_4
+
+0x00a000:0x00afff 00_5
+0x00b000:0x00bfff ff_5
+
+0x00c000:0x00cfff 00_6
+0x00d000:0x00dfff ff_6
+
+0x00e000:0x00efff 00_7
+0x00f000:0x00ffff ff_7
+
+0x010000:0x010fff 00_8
+0x011000:0x011fff ff_8
+
+0x012000:0x012fff 00_9
+0x013000:0x013fff ff_9
+
+0x014000:0x014fff 00_10
+0x015000:0x015fff ff_10
+
+0x016000:0x016fff 00_11
+0x017000:0x017fff ff_11
+
+0x018000:0x018fff 00_12
+0x019000:0x019fff ff_12
+
+0x01a000:0x01afff 00_13
+0x01b000:0x01bfff ff_13
+
+0x01c000:0x01cfff 00_14
+0x01d000:0x01dfff ff_14
+
+0x01e000:0x01efff 00_15
+0x01f000:0x01ffff ff_15
+" > layout_4k_aligned.txt
+
+cp "$BIOS" "$TESTFILE"
+i=0
+while [ $i -lt $NUM_REGIONS ] ; do
+       echo -n "aligned region ${i} test: "
+       offset=$((${i} * 8192))
+       dd if=${ZERO_4K} of=${TESTFILE} bs=1 conv=notrunc seek=${offset} 2> /dev/null
+       dd if=${FF_4K} of=${TESTFILE} bs=1 conv=notrunc seek=$((${offset} + 4096)) 2> /dev/null
+
+       ./flashrom ${FLASHROM_PARAM} -l layout_4k_aligned.txt -i 00_${i} -i ff_${i} -w "$TESTFILE" > /dev/null
+       if [ "$?" != "0" ] ; then
+               echo "failed to flash region"
+               do_exit "$EXIT_FAILURE"
+       fi
+
+       # download the entire ROM image and use diff to compare to ensure
+       # flashrom logic does not violate user-specified regions
+       flashrom ${FLASHROM_PARAM} -r difftest.bin > /dev/null
+       diff -q difftest.bin "$TESTFILE"
+       if [ "$?" != "0" ] ; then
+               echo "failed diff test"
+               do_exit "$EXIT_FAILURE"
+       fi
+       rm -f difftest.bin
+
+       i=$((${i} + 1))
+       echo "passed"
+done
+
+# Make a layout - 4K regions on 4.5K boundaries. This will help find problems
+# with logic that only operates on part of a block. For example, if a user
+# wishes to re-write a fraction of a block, then:
+# 1. The whole block must be erased.
+# 2. The old content must be restored at unspecified offsets.
+# 3. The new content must be written at specified offsets.
+#
+# Note: The last chunk of 0xff bytes is only 2k as to avoid overrunning a 128kB
+# test image.
+#
+echo "
+0x000800:0x0017ff 00_0
+0x001800:0x0027ff ff_0
+
+0x002800:0x0037ff 00_1
+0x003800:0x0047ff ff_1
+
+0x004800:0x0057ff 00_2
+0x005800:0x0067ff ff_2
+
+0x006800:0x0077ff 00_3
+0x007800:0x0087ff ff_3
+
+0x008800:0x0097ff 00_4
+0x009800:0x00a7ff ff_4
+
+0x00a800:0x00b7ff 00_5
+0x00b800:0x00c7ff ff_5
+
+0x00c800:0x00d7ff 00_6
+0x00d800:0x00e7ff ff_6
+
+0x00e800:0x00f7ff 00_7
+0x00f800:0x0107ff ff_7
+
+0x010800:0x0117ff 00_8
+0x011800:0x0127ff ff_8
+
+0x012800:0x0137ff 00_9
+0x013800:0x0147ff ff_9
+
+0x014800:0x0157ff 00_10
+0x015800:0x0167ff ff_10
+
+0x016800:0x0177ff 00_11
+0x017800:0x0187ff ff_11
+
+0x018800:0x0197ff 00_12
+0x019800:0x01a7ff ff_12
+
+0x01a800:0x01b7ff 00_13
+0x01b800:0x01c7ff ff_13
+
+0x01c800:0x01d7ff 00_14
+0x01d800:0x01e7ff ff_14
+
+0x01e800:0x01f7ff 00_15
+0x01f800:0x01ffff ff_15
+" > layout_unaligned.txt
+
+# reset the test file and ROM to the original state
+flashrom ${FLASHROM_PARAM} -w "$BIOS" > /dev/null
+cp "$BIOS" "$TESTFILE"
+
+i=0
+while [ $i -lt $NUM_REGIONS ] ; do
+       echo -n "unaligned region ${i} test: "
+
+       offset=$(($((${i} * 8192)) + 2048))
+       # Protect against too long write
+       writelen=4096
+       if [ $((${offset} + 4096 + 4096)) -ge 131072 ]; then
+               writelen=$((131072 - $((${offset} + 4096))))
+               if [ ${writelen} -lt 0 ]; then
+                       writelen=0
+               fi
+       fi
+       dd if=${ZERO_4K} of=${TESTFILE} bs=1 conv=notrunc seek=${offset} 2> /dev/null
+       dd if=${FF_4K} of=${TESTFILE} bs=1 conv=notrunc seek=$((${offset} + 4096)) count=writelen 2> /dev/null
+
+       ./flashrom ${FLASHROM_PARAM} -l layout_unaligned.txt -i 00_${i} -i ff_${i} -w "$TESTFILE" > /dev/null
+       if [ "$?" != "0" ] ; then
+               echo "failed to flash region"
+               do_exit "$EXIT_FAILURE"
+       fi
+
+       # download the entire ROM image and use diff to compare to ensure
+       # flashrom logic does not violate user-specified regions
+       flashrom ${FLASHROM_PARAM} -r difftest.bin > /dev/null
+       diff -q difftest.bin "$TESTFILE"
+       if [ "$?" != "0" ] ; then
+               echo "failed diff test"
+               do_exit "$EXIT_FAILURE"
+       fi
+       rm -f difftest.bin
+
+       i=$((${i} + 1))
+       echo "passed"
+done
+
+do_exit "$EXIT_SUCCESS"
diff --git a/util/ich_descriptors_tool/Makefile b/util/ich_descriptors_tool/Makefile
new file mode 100644 (file)
index 0000000..1af90ce
--- /dev/null
@@ -0,0 +1,42 @@
+CC ?= gcc
+
+PROGRAM=ich_descriptors_tool
+EXTRAINCDIRS = ../../ .
+DEPPATH = .dep
+OBJATH = .obj
+SHAREDSRC = ich_descriptors.c
+SHAREDSRCDIR = ../..
+
+SRC = $(wildcard *.c)
+
+CFLAGS += -Wall
+CFLAGS += -MMD -MP -MF $(DEPPATH)/$(@F).d
+# enables functions that populate the descriptor structs from plain binary dumps
+CFLAGS += -D ICH_DESCRIPTORS_FROM_DUMP
+CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
+
+OBJ = $(OBJATH)/$(SRC:%.c=%.o)
+
+SHAREDOBJ = $(OBJATH)/$(notdir $(SHAREDSRC:%.c=%.o))
+
+all:$(PROGRAM)
+
+$(OBJ): $(OBJATH)/%.o : %.c
+       $(CC) $(CFLAGS) -o $@ -c $<
+
+# this enables us to share source files without simultaneously sharing .o files
+# with flashrom, which would lead to unexpected results (w/o running make clean)
+$(SHAREDOBJ): $(OBJATH)/%.o : $(SHAREDSRCDIR)/%.c
+       $(CC) $(CFLAGS) -o $@ -c $<
+
+$(PROGRAM): $(OBJ) $(SHAREDOBJ)
+       $(CC) -o $(PROGRAM) $(OBJ) $(SHAREDOBJ)
+
+clean:
+       rm -f $(PROGRAM)
+       rm -rf $(DEPPATH) $(OBJATH)
+
+# Include the dependency files.
+-include $(shell mkdir -p $(DEPPATH) $(OBJATH) 2>/dev/null) $(wildcard $(DEPPATH)/*)
+
+.PHONY: all clean
diff --git a/util/ich_descriptors_tool/TODO b/util/ich_descriptors_tool/TODO
new file mode 100644 (file)
index 0000000..e1bb843
--- /dev/null
@@ -0,0 +1,10 @@
+- reverse the path: assemble a descriptormode image from various
+  blobs (BIOS, GbE, ME, OEM) and a description (xml? custom config?
+  sane defaults and cmd-line switches?)
+- dump 256 OEM bytes
+- deal with the various possible locations of mac address(es?)
+       /* mazzoo said: from what I've seen, the MAC address is the 1st or
+        * 2nd 6 bytes in the GbE region. It seems the PXE-OpROM and/or the
+        * intel EEUPDATE-tool copies the MAC address to the 2nd part.
+        */
+- add descriptions for the missing chipsets
diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c
new file mode 100644 (file)
index 0000000..a1bce1b
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010  Matthias Wenzel <bios at mazzoo dot de>
+ * Copyright (C) 2011 Stefan Tauner
+ *
+ * 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
+ */
+
+/*
+ * dump information and binaries from BIOS images that are in descriptor mode
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "ich_descriptors.h"
+
+static void dump_file(const char *basename, const uint32_t *dump, unsigned int len, struct ich_desc_region *reg, unsigned int i)
+{
+       int ret;
+       char *fn;
+       const char *reg_name;
+       uint32_t file_len;
+       const char *const region_names[5] = {
+               "Descriptor", "BIOS", "ME", "GbE", "Platform"
+       };
+       uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]);
+       uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]);
+
+       reg_name = region_names[i];
+       if (base > limit) {
+               printf("The %s region is unused and thus not dumped.\n",
+                      reg_name);
+               return;
+       }
+
+       limit = limit | 0x0fff;
+       file_len = limit + 1 - base;
+       if (base + file_len > len) {
+               printf("The %s region is spanning 0x%08x-0x%08x, but it is "
+                      "not (fully) included in the image (0-0x%08x), thus not "
+                      "dumped.\n", reg_name, base, limit, len - 1);
+               return;
+       }
+
+       fn = malloc(strlen(basename) + strlen(reg_name) + strlen(".bin") + 2);
+       if (!fn) {
+               fprintf(stderr, "Out of memory!\n");
+               exit(1);
+       }
+       snprintf(fn, strlen(basename) + strlen(reg_name) + strlen(".bin") + 2,
+                "%s.%s.bin", basename, reg_name);
+       printf("Dumping %u bytes of the %s region from 0x%08x-0x%08x to %s... ",
+              file_len, region_names[i], base, limit, fn);
+       int fh = open(fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+       free(fn);
+       if (fh < 0) {
+               fprintf(stderr,
+                       "ERROR: couldn't open(%s): %s\n", fn, strerror(errno));
+               exit(1);
+       }
+
+       ret = write(fh, &dump[base >> 2], file_len);
+       if (ret != file_len) {
+               fprintf(stderr, "FAILED.\n");
+               exit(1);
+       }
+
+       printf("done.\n");
+       close(fh);
+}
+
+void dump_files(const char *n, const uint32_t *buf, unsigned int len, struct ich_desc_region *reg)
+{
+       unsigned int i;
+       printf("=== Dumping region files ===\n");
+       for (i = 0; i < 5; i++)
+               dump_file(n, buf, len, reg, i);
+       printf("\n");
+}
+
+static void usage(char *argv[], char *error)
+{
+       if (error != NULL) {
+               fprintf(stderr, "%s\n", error);
+       }
+       printf("usage: '%s -f <image file name> [-c <chipset name>] [-d]'\n\n"
+"where <image file name> points to an image of the contents of the SPI flash.\n"
+"In case the image is really in descriptor mode %s\n"
+"will pretty print some of the contained information.\n"
+"To also print the data stored in the descriptor strap you have to indicate\n"
+"the chipset series with the '-c' parameter and one of the possible arguments:\n"
+"\t- \"ich8\",\n"
+"\t- \"ich9\",\n"
+"\t- \"ich10\",\n"
+"\t- \"5\" or \"ibex\" for Intel's 5 series chipsets,\n"
+"\t- \"6\" or \"cougar\" for Intel's 6 series chipsets,\n"
+"\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n"
+"If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n"
+"the GbE blob that is required to initialize the GbE are also dumped to files.\n",
+       argv[0], argv[0]);
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       int fd;                 /* file descriptor to flash file */
+       int len;                /* file/buffer size in bytes */
+       uint32_t *buf;          /* mmap'd file */
+       uint8_t *pMAC;
+       int opt, ret;
+
+       int dump = 0;
+       const char *fn = NULL;
+       const char *csn = NULL;
+       enum ich_chipset cs = CHIPSET_ICH_UNKNOWN;
+       struct ich_descriptors desc = {{ 0 }};
+
+       while ((opt = getopt(argc, argv, "df:c:")) != -1) {
+               switch (opt) {
+               case 'd':
+                       dump = 1;
+                       break;
+               case 'f':
+                       fn = optarg;
+                       break;
+               case 'c':
+                       csn = optarg;
+                       break;
+               default: /* '?' */
+                       usage(argv, NULL);
+               }
+       }
+       if (fn == NULL)
+               usage(argv,
+                     "Need a file name of a descriptor image to read from.");
+
+       fd = open(fn, O_RDONLY);
+       if (fd < 0)
+               usage(argv, "No such file");
+       len = lseek(fd, 0, SEEK_END);
+       if (len < 0)
+               usage(argv, "Seeking to the end of the file failed");
+
+       buf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (buf == (void *) -1) {
+               /* fallback for stupid OSes like cygwin */
+               int ret;
+               buf = malloc(len);
+               if (!buf)
+                       usage(argv, "Could not allocate memory");
+               lseek(fd, 0, SEEK_SET);
+               ret = read(fd, buf, len);
+               if (ret != len)
+                       usage(argv, "Seeking to the end of the file failed");
+       }
+       printf("The flash image has a size of %d [0x%x] bytes.\n", len, len);
+       close(fd);
+
+       if (csn != NULL) {
+               if (strcmp(csn, "ich8") == 0)
+                       cs = CHIPSET_ICH8;
+               else if (strcmp(csn, "ich9") == 0)
+                       cs = CHIPSET_ICH9;
+               else if (strcmp(csn, "ich10") == 0)
+                       cs = CHIPSET_ICH10;
+               else if ((strcmp(csn, "5") == 0) ||
+                        (strcmp(csn, "ibex") == 0))
+                       cs = CHIPSET_5_SERIES_IBEX_PEAK;
+               else if ((strcmp(csn, "6") == 0) ||
+                        (strcmp(csn, "cougar") == 0))
+                       cs = CHIPSET_6_SERIES_COUGAR_POINT;
+               else if ((strcmp(csn, "7") == 0) ||
+                        (strcmp(csn, "panther") == 0))
+                       cs = CHIPSET_7_SERIES_PANTHER_POINT;
+       }
+
+       ret = read_ich_descriptors_from_dump(buf, len, &desc);
+       switch (ret) {
+       case ICH_RET_OK:
+               break;
+       case ICH_RET_ERR:
+               printf("Image not in descriptor mode.\n");
+               exit(1);
+       case ICH_RET_OOB:
+               printf("Tried to access a location out of bounds of the image. "
+                      "- Corrupt image?\n");
+               exit(1);
+       default:
+               printf("Unhandled return value at %s:%u, please report this.\n",
+                      __FILE__, __LINE__);
+               exit(1);
+       }
+
+       prettyprint_ich_descriptors(cs, &desc);
+
+       pMAC = (uint8_t *) &buf[ICH_FREG_BASE(desc.region.reg3_base) >> 2];
+       if (len >= ICH_FREG_BASE(desc.region.reg3_base) + 5 && pMAC[0] != 0xff)
+               printf("The MAC address might be at offset 0x%x: "
+                      "%02x:%02x:%02x:%02x:%02x:%02x\n",
+                      ICH_FREG_BASE(desc.region.reg3_base),
+                      pMAC[0], pMAC[1], pMAC[2], pMAC[3], pMAC[4], pMAC[5]);
+
+       if (dump == 1)
+               dump_files(fn, buf, len, &desc.region);
+
+       return 0;
+}
diff --git a/util/z60_flashrom.rules b/util/z60_flashrom.rules
new file mode 100644 (file)
index 0000000..8456a04
--- /dev/null
@@ -0,0 +1,83 @@
+##
+## This file is part of the flashrom project.
+##
+## Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+##
+## Please keep this list sorted alphabetically by vendor/device name.
+##
+
+##
+## This is tested on udev version 154, other versions may need small fixes.
+##
+## Note that you might want to change the "plugdev" group to whatever is
+## suitable for your respective distribution.
+##
+
+ACTION!="add|change", GOTO="flashrom_rules_end"
+SUBSYSTEM!="usb|usb_device", GOTO="flashrom_rules_end"
+
+# Amontec JTAGkey(2)
+# http://www.amontec.com/jtagkey.shtml
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="664", GROUP="plugdev"
+
+# Buspirate
+# http://dangerousprototypes.com/2009/10/08/bus-pirate-raw-spi-mode/
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"
+
+# Dediprog SF100
+# http://www.dediprog.com/SPI-flash-in-circuit-programming/SF100
+ATTRS{idVendor}=="0483", ATTRS{idProduct}=="dada", MODE="664", GROUP="plugdev"
+
+# DLP Design DLP-USB1232H
+# http://www.dlpdesign.com/usb/usb1232h.shtml
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev"
+
+# FIC OpenMoko Neo1973 Debug board (V2+)
+# http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v2
+ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="664", GROUP="plugdev"
+
+# FTDI FT4232H Mini-Module
+# http://www.ftdichip.com/Products/EvaluationKits/FT4232H_MiniModule.htm
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="664", GROUP="plugdev"
+
+# GOEPEL PicoTAP
+# http://www.goepel.com/jtagboundary-scan/hardware/picotap.html
+ATTRS{idVendor}=="096c", ATTRS{idProduct}=="1449", MODE="664", GROUP="plugdev"
+
+# Olimex ARM-USB-OCD
+# http://olimex.com/dev/arm-usb-ocd.html
+ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="664", GROUP="plugdev"
+
+# Olimex ARM-USB-OCD-H
+# http://olimex.com/dev/arm-usb-ocd-h.html
+ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="664", GROUP="plugdev"
+
+# Olimex ARM-USB-TINY
+# http://olimex.com/dev/arm-usb-tiny.html
+ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="664", GROUP="plugdev"
+
+# Olimex ARM-USB-TINY-H
+# http://olimex.com/dev/arm-usb-tiny-h.html
+ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="664", GROUP="plugdev"
+
+# TIAO/DIYGADGET USB Multi-Protocol Adapter (TUMPA)
+# http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="664", GROUP="plugdev"
+
+LABEL="flashrom_rules_end"
diff --git a/w29ee011.c b/w29ee011.c
new file mode 100644 (file)
index 0000000..d2af23d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2007 Markus Boas <ryven@ryven.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include "flash.h"
+
+/* According to the Winbond W29EE011, W29EE012, W29C010M, W29C011A
+ * datasheets this is the only valid probe function for those chips.
+ */
+int probe_w29ee011(struct flashctx *flash)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t id1, id2;
+
+       if (!chip_to_probe || strcmp(chip_to_probe, flash->name)) {
+               msg_cdbg("Old Winbond W29* probe method disabled because "
+                        "the probing sequence puts the AMIC A49LF040A in "
+                        "a funky state. Use 'flashrom -c %s' if you "
+                        "have a board with such a chip.\n", flash->name);
+               return 0;
+       }
+
+       /* Issue JEDEC Product ID Entry command */
+       chip_writeb(flash, 0xAA, bios + 0x5555);
+       programmer_delay(10);
+       chip_writeb(flash, 0x55, bios + 0x2AAA);
+       programmer_delay(10);
+       chip_writeb(flash, 0x80, bios + 0x5555);
+       programmer_delay(10);
+       chip_writeb(flash, 0xAA, bios + 0x5555);
+       programmer_delay(10);
+       chip_writeb(flash, 0x55, bios + 0x2AAA);
+       programmer_delay(10);
+       chip_writeb(flash, 0x60, bios + 0x5555);
+       programmer_delay(10);
+
+       /* Read product ID */
+       id1 = chip_readb(flash, bios);
+       id2 = chip_readb(flash, bios + 0x01);
+
+       /* Issue JEDEC Product ID Exit command */
+       chip_writeb(flash, 0xAA, bios + 0x5555);
+       programmer_delay(10);
+       chip_writeb(flash, 0x55, bios + 0x2AAA);
+       programmer_delay(10);
+       chip_writeb(flash, 0xF0, bios + 0x5555);
+       programmer_delay(10);
+
+       msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+
+       if (id1 == flash->manufacture_id && id2 == flash->model_id)
+               return 1;
+
+       return 0;
+}
diff --git a/w39.c b/w39.c
new file mode 100644 (file)
index 0000000..5f0c347
--- /dev/null
+++ b/w39.c
@@ -0,0 +1,288 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 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
+ * 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 printlock_w39_fwh_block(struct flashctx *flash, unsigned int offset)
+{
+       chipaddr wrprotect = flash->virtual_registers + offset + 2;
+       uint8_t locking;
+
+       locking = chip_readb(flash, wrprotect);
+       msg_cdbg("Lock status of block at 0x%08x is ", offset);
+       switch (locking & 0x7) {
+       case 0:
+               msg_cdbg("Full Access.\n");
+               break;
+       case 1:
+               msg_cdbg("Write Lock (Default State).\n");
+               break;
+       case 2:
+               msg_cdbg("Locked Open (Full Access, Lock Down).\n");
+               break;
+       case 3:
+               msg_cerr("Error: Write Lock, Locked Down.\n");
+               break;
+       case 4:
+               msg_cdbg("Read Lock.\n");
+               break;
+       case 5:
+               msg_cdbg("Read/Write Lock.\n");
+               break;
+       case 6:
+               msg_cerr("Error: Read Lock, Locked Down.\n");
+               break;
+       case 7:
+               msg_cerr("Error: Read/Write Lock, Locked Down.\n");
+               break;
+       }
+
+       /* Read or write lock present? */
+       return (locking & ((1 << 2) | (1 << 0))) ? -1 : 0;
+}
+
+static int unlock_w39_fwh_block(struct flashctx *flash, unsigned int offset)
+{
+       chipaddr wrprotect = flash->virtual_registers + offset + 2;
+       uint8_t locking;
+
+       locking = chip_readb(flash, wrprotect);
+       /* Read or write lock present? */
+       if (locking & ((1 << 2) | (1 << 0))) {
+               /* Lockdown active? */
+               if (locking & (1 << 1)) {
+                       msg_cerr("Can't unlock block at 0x%08x!\n", offset);
+                       return -1;
+               } else {
+                       msg_cdbg("Unlocking block at 0x%08x\n", offset);
+                       chip_writeb(flash, 0, wrprotect);
+               }
+       }
+
+       return 0;
+}
+
+static uint8_t w39_idmode_readb(struct flashctx *flash, unsigned int offset)
+{
+       chipaddr bios = flash->virtual_memory;
+       uint8_t val;
+
+       /* Product Identification Entry */
+       chip_writeb(flash, 0xAA, bios + 0x5555);
+       chip_writeb(flash, 0x55, bios + 0x2AAA);
+       chip_writeb(flash, 0x90, bios + 0x5555);
+       programmer_delay(10);
+
+       /* Read something, maybe hardware lock bits */
+       val = chip_readb(flash, bios + offset);
+
+       /* Product Identification Exit */
+       chip_writeb(flash, 0xAA, bios + 0x5555);
+       chip_writeb(flash, 0x55, bios + 0x2AAA);
+       chip_writeb(flash, 0xF0, bios + 0x5555);
+       programmer_delay(10);
+
+       return val;
+}
+
+static int printlock_w39_tblwp(uint8_t lock)
+{
+       msg_cdbg("Hardware bootblock locking (#TBL) is %sactive.\n",
+                (lock & (1 << 2)) ? "" : "not ");
+       msg_cdbg("Hardware remaining chip locking (#WP) is %sactive..\n",
+               (lock & (1 << 3)) ? "" : "not ");
+       if (lock & ((1 << 2) | (1 << 3)))
+               return -1;
+
+       return 0;
+}
+
+static int printlock_w39_bootblock_64k16k(uint8_t lock)
+{
+       msg_cdbg("Software 64 kB bootblock locking is %sactive.\n",
+                (lock & (1 << 0)) ? "" : "not ");
+       msg_cdbg("Software 16 kB bootblock locking is %sactive.\n",
+                (lock & (1 << 1)) ? "" : "not ");
+       if (lock & ((1 << 1) | (1 << 0)))
+               return -1;
+
+       return 0;
+}
+
+static int printlock_w39_common(struct flashctx *flash, unsigned int offset)
+{
+       uint8_t lock;
+
+       lock = w39_idmode_readb(flash, offset);
+       msg_cdbg("Lockout bits:\n");
+       return printlock_w39_tblwp(lock);
+}
+
+static int printlock_w39_fwh(struct flashctx *flash)
+{
+       unsigned int i, total_size = flash->total_size * 1024;
+       int ret = 0;
+       
+       /* Print lock status of the complete chip */
+       for (i = 0; i < total_size; i += flash->page_size)
+               ret |= printlock_w39_fwh_block(flash, i);
+
+       return ret;
+}
+
+static int unlock_w39_fwh(struct flashctx *flash)
+{
+       unsigned int i, total_size = flash->total_size * 1024;
+       
+       /* Unlock the complete chip */
+       for (i = 0; i < total_size; i += flash->page_size)
+               if (unlock_w39_fwh_block(flash, i))
+                       return -1;
+
+       return 0;
+}
+
+int printlock_w39l040(struct flashctx *flash)
+{
+       uint8_t lock;
+       int ret;
+
+       lock = w39_idmode_readb(flash, 0x00002);
+       msg_cdbg("Bottom boot block:\n");
+       ret = printlock_w39_bootblock_64k16k(lock);
+
+       lock = w39_idmode_readb(flash, 0x7fff2);
+       msg_cdbg("Top boot block:\n");
+       ret |= printlock_w39_bootblock_64k16k(lock);
+
+       return ret;
+}
+
+int printlock_w39v040a(struct flashctx *flash)
+{
+       uint8_t lock;
+       int ret = 0;
+
+       /* The W39V040A datasheet contradicts itself on the lock register
+        * location: 0x00002 and 0x7fff2 are both mentioned. Pick the one
+        * which is similar to the other chips of the same family.
+        */
+       lock = w39_idmode_readb(flash, 0x7fff2);
+       msg_cdbg("Lockout bits:\n");
+
+       ret = printlock_w39_tblwp(lock);
+       ret |= printlock_w39_bootblock_64k16k(lock);
+
+       return ret;
+}
+
+int printlock_w39v040b(struct flashctx *flash)
+{
+       return printlock_w39_common(flash, 0x7fff2);
+}
+
+int printlock_w39v040c(struct flashctx *flash)
+{
+       /* Typo in the datasheet? The other chips use 0x7fff2. */
+       return printlock_w39_common(flash, 0xfff2);
+}
+
+int printlock_w39v040fa(struct flashctx *flash)
+{
+       int ret = 0;
+
+       ret = printlock_w39v040a(flash);
+       ret |= printlock_w39_fwh(flash);
+
+       return ret;
+}
+
+int printlock_w39v040fb(struct flashctx *flash)
+{
+       int ret = 0;
+
+       ret = printlock_w39v040b(flash);
+       ret |= printlock_w39_fwh(flash);
+
+       return ret;
+}
+
+int printlock_w39v040fc(struct flashctx *flash)
+{
+       int ret = 0;
+
+       /* W39V040C and W39V040FC use different WP/TBL offsets. */
+       ret = printlock_w39_common(flash, 0x7fff2);
+       ret |= printlock_w39_fwh(flash);
+
+       return ret;
+}
+
+int printlock_w39v080a(struct flashctx *flash)
+{
+       return printlock_w39_common(flash, 0xffff2);
+}
+
+int printlock_w39v080fa(struct flashctx *flash)
+{
+       int ret = 0;
+
+       ret = printlock_w39v080a(flash);
+       ret |= printlock_w39_fwh(flash);
+
+       return ret;
+}
+
+int printlock_w39v080fa_dual(struct flashctx *flash)
+{
+       msg_cinfo("Block locking for W39V080FA in dual mode is "
+                 "undocumented.\n");
+       /* Better safe than sorry. */
+       return -1;
+}
+
+int unlock_w39v040fb(struct flashctx *flash)
+{
+       if (unlock_w39_fwh(flash))
+               return -1;
+       if (printlock_w39_common(flash, 0x7fff2))
+               return -1;
+
+       return 0;
+}
+
+int unlock_w39v080fa(struct flashctx *flash)
+{
+       if (unlock_w39_fwh(flash))
+               return -1;
+       if (printlock_w39_common(flash, 0xffff2))
+               return -1;
+
+       return 0;
+}
+
+int printlock_at49f(struct flashctx *flash)
+{
+       uint8_t lock = w39_idmode_readb(flash, 0x00002);
+       msg_cdbg("Hardware bootblock lockout is %sactive.\n",
+                (lock & 0x01) ? "" : "not ");
+       return 0;
+}
diff --git a/wbsio_spi.c b/wbsio_spi.c
new file mode 100644 (file)
index 0000000..7d4bb2a
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Peter Stuge <peter@stuge.se>
+ * 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; 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
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "hwaccess.h"
+#include "spi.h"
+
+#define WBSIO_PORT1    0x2e
+#define WBSIO_PORT2    0x4e
+
+static uint16_t wbsio_spibase = 0;
+
+static uint16_t wbsio_get_spibase(uint16_t port)
+{
+       uint8_t id;
+       uint16_t flashport = 0;
+
+       w836xx_ext_enter(port);
+       id = sio_read(port, 0x20);
+       if (id != 0xa0) {
+               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)) {
+               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)) {
+               msg_perr("\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port);
+               goto done;
+       }
+
+       flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63);
+
+done:
+       w836xx_ext_leave(port);
+       return flashport;
+}
+
+static int wbsio_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                                 unsigned int readcnt,
+                                 const unsigned char *writearr,
+                                 unsigned char *readarr);
+static int wbsio_spi_read(struct flashctx *flash, uint8_t *buf,
+                         unsigned int start, unsigned int len);
+
+static const struct spi_programmer spi_programmer_wbsio = {
+       .type = SPI_CONTROLLER_WBSIO,
+       .max_data_read = MAX_DATA_UNSPECIFIED,
+       .max_data_write = MAX_DATA_UNSPECIFIED,
+       .command = wbsio_spi_send_command,
+       .multicommand = default_spi_send_multicommand,
+       .read = wbsio_spi_read,
+       .write_256 = spi_chip_write_1,
+       .write_aai = default_spi_write_aai,
+};
+
+int wbsio_check_for_spi(void)
+{
+       if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1)))
+               if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2)))
+                       return 1;
+
+       msg_pspew("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
+
+       msg_pdbg("%s: Winbond saved on 4 register bits so max chip size is "
+                "1024 kB!\n", __func__);
+       max_rom_decode.spi = 1024 * 1024;
+       register_spi_programmer(&spi_programmer_wbsio);
+
+       return 0;
+}
+
+/* W83627DHG has 11 command modes:
+ * 1=1 command only
+ * 2=1 command+1 data write
+ * 3=1 command+2 data read
+ * 4=1 command+3 address
+ * 5=1 command+3 address+1 data write
+ * 6=1 command+3 address+4 data write
+ * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read
+ * 8=1 command+3 address+1 data read
+ * 9=1 command+3 address+2 data read
+ * a=1 command+3 address+3 data read
+ * b=1 command+3 address+4 data read
+ *
+ * mode[7:4] holds the command mode
+ * mode[3:0] holds SPI address bits [19:16]
+ *
+ * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\
+ * Would one more byte of RAM in the chip (to get all 24 bits) really make
+ * such a big difference?
+ */
+static int wbsio_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+                                 unsigned int readcnt,
+                                 const unsigned char *writearr,
+                                 unsigned char *readarr)
+{
+       int i;
+       uint8_t mode = 0;
+
+       msg_pspew("%s:", __func__);
+
+       if (1 == writecnt && 0 == readcnt) {
+               mode = 0x10;
+       } else if (2 == writecnt && 0 == readcnt) {
+               OUTB(writearr[1], wbsio_spibase + 4);
+               msg_pspew(" data=0x%02x", writearr[1]);
+               mode = 0x20;
+       } else if (1 == writecnt && 2 == readcnt) {
+               mode = 0x30;
+       } else if (4 == writecnt && 0 == readcnt) {
+               msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
+               for (i = 2; i < writecnt; i++) {
+                       OUTB(writearr[i], wbsio_spibase + i);
+                       msg_pspew("%02x", writearr[i]);
+               }
+               mode = 0x40 | (writearr[1] & 0x0f);
+       } else if (5 == writecnt && 0 == readcnt) {
+               msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
+               for (i = 2; i < 4; i++) {
+                       OUTB(writearr[i], wbsio_spibase + i);
+                       msg_pspew("%02x", writearr[i]);
+               }
+               OUTB(writearr[i], wbsio_spibase + i);
+               msg_pspew(" data=0x%02x", writearr[i]);
+               mode = 0x50 | (writearr[1] & 0x0f);
+       } else if (8 == writecnt && 0 == readcnt) {
+               msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
+               for (i = 2; i < 4; i++) {
+                       OUTB(writearr[i], wbsio_spibase + i);
+                       msg_pspew("%02x", writearr[i]);
+               }
+               msg_pspew(" data=0x");
+               for (; i < writecnt; i++) {
+                       OUTB(writearr[i], wbsio_spibase + i);
+                       msg_pspew("%02x", writearr[i]);
+               }
+               mode = 0x60 | (writearr[1] & 0x0f);
+       } else if (5 == writecnt && 4 == readcnt) {
+               /* XXX: TODO not supported by flashrom infrastructure!
+                * This mode, 7, discards the fifth byte in writecnt,
+                * but since we can not express that in flashrom, fail
+                * the operation for now.
+                */
+               ;
+       } else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) {
+               msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
+               for (i = 2; i < writecnt; i++) {
+                       OUTB(writearr[i], wbsio_spibase + i);
+                       msg_pspew("%02x", writearr[i]);
+               }
+               mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f);
+       }
+       msg_pspew(" cmd=%02x mode=%02x\n", writearr[0], mode);
+
+       if (!mode) {
+               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;
+       }
+
+       OUTB(writearr[0], wbsio_spibase);
+       OUTB(mode, wbsio_spibase + 1);
+       programmer_delay(10);
+
+       if (!readcnt)
+               return 0;
+
+       msg_pspew("%s: returning data =", __func__);
+       for (i = 0; i < readcnt; i++) {
+               readarr[i] = INB(wbsio_spibase + 4 + i);
+               msg_pspew(" 0x%02x", readarr[i]);
+       }
+       msg_pspew("\n");
+       return 0;
+}
+
+static int wbsio_spi_read(struct flashctx *flash, uint8_t *buf,
+                         unsigned int start, unsigned int len)
+{
+       mmio_readn((void *)(flash->virtual_memory + start), buf, len);
+       return 0;
+}
+
+#endif