diff --git a/initrd/bin/flashrom-x230.sh b/initrd/bin/flashrom-x230.sh
index ee978f32..0ca6f079 100755
--- a/initrd/bin/flashrom-x230.sh
+++ b/initrd/bin/flashrom-x230.sh
@@ -24,7 +24,7 @@ flashrom \
 	--force \
 	--noverify \
 	--programmer internal \
-	--layout /etc/x230-layout.txt \
+	--ifd \
 	--image BIOS \
 	-w /tmp/x230.rom \
 || die "$ROM: Flash failed"
diff --git a/initrd/etc/x230-layout.txt b/initrd/etc/x230-layout.txt
deleted file mode 100644
index 8bdc2bea..00000000
--- a/initrd/etc/x230-layout.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-00000000:00000FFF Descriptor     
-00001000:00002FFF GBe                   
-00003000:004FFFFF ME              
-00500000:00BFFFFF BIOS                  
diff --git a/patches/flashrom-0.9.9.patch b/patches/flashrom-0.9.9.patch
deleted file mode 100644
index 4765465e..00000000
--- a/patches/flashrom-0.9.9.patch
+++ /dev/null
@@ -1,2685 +0,0 @@
-diff --git ./Makefile ./Makefile
-index 4ebde1e..4257e82 100644
---- ./Makefile
-+++ ./Makefile
-@@ -214,6 +214,16 @@ UNSUPPORTED_FEATURES += CONFIG_GFXNVIDIA=yes
- else
- override CONFIG_GFXNVIDIA = no
- endif
-+ifeq ($(CONFIG_AST1100), yes)
-+UNSUPPORTED_FEATURES += CONFIG_AST1100=yes
-+else
-+override CONFIG_AST1100 = no
-+endif
-+ifeq ($(CONFIG_AST2400), yes)
-+UNSUPPORTED_FEATURES += CONFIG_AST2400=yes
-+else
-+override CONFIG_AST2400 = no
-+endif
- ifeq ($(CONFIG_SATASII), yes)
- UNSUPPORTED_FEATURES += CONFIG_SATASII=yes
- else
-@@ -441,6 +451,16 @@ UNSUPPORTED_FEATURES += CONFIG_GFXNVIDIA=yes
- else
- override CONFIG_GFXNVIDIA = no
- endif
-+ifeq ($(CONFIG_AST1100), yes)
-+UNSUPPORTED_FEATURES += CONFIG_AST1100=yes
-+else
-+override CONFIG_AST1100 = no
-+endif
-+ifeq ($(CONFIG_AST2400), yes)
-+UNSUPPORTED_FEATURES += CONFIG_AST2400=yes
-+else
-+override CONFIG_AST2400 = no
-+endif
- ifeq ($(CONFIG_SATASII), yes)
- UNSUPPORTED_FEATURES += CONFIG_SATASII=yes
- else
-@@ -514,7 +534,7 @@ endif
- CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \
- 	sst28sf040.o 82802ab.o \
- 	sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o \
--	opaque.o sfdp.o en29lv640b.o at45db.o
-+	spi4ba.o opaque.o sfdp.o en29lv640b.o at45db.o
- 
- ###############################################################################
- # Library code.
-@@ -565,6 +585,12 @@ CONFIG_NIC3COM ?= yes
- # Enable NVIDIA graphics cards. Note: write and erase do not work properly.
- CONFIG_GFXNVIDIA ?= yes
- 
-+# Enable AST1100 BMC SoCs.
-+CONFIG_AST1100 ?= yes
-+
-+# Enable AST2400 BMC SoCs.
-+CONFIG_AST2400 ?= yes
-+
- # Always enable SiI SATA controllers for now.
- CONFIG_SATASII ?= yes
- 
-@@ -664,6 +690,8 @@ ifeq ($(CONFIG_ENABLE_LIBPCI_PROGRAMMERS), no)
- override CONFIG_INTERNAL = no
- override CONFIG_NIC3COM = no
- override CONFIG_GFXNVIDIA = no
-+override CONFIG_AST1100 = no
-+override CONFIG_AST2400 = no
- override CONFIG_SATASII = no
- override CONFIG_ATAHPT = no
- override CONFIG_ATAVIA = no
-@@ -776,6 +804,18 @@ PROGRAMMER_OBJS += gfxnvidia.o
- NEED_LIBPCI += CONFIG_GFXNVIDIA
- endif
- 
-+ifeq ($(CONFIG_AST1100), yes)
-+FEATURE_CFLAGS += -D'CONFIG_AST1100=1'
-+PROGRAMMER_OBJS += ast1100.o
-+NEED_LIBPCI += CONFIG_AST1100
-+endif
-+
-+ifeq ($(CONFIG_AST2400), yes)
-+FEATURE_CFLAGS += -D'CONFIG_AST2400=1'
-+PROGRAMMER_OBJS += ast2400.o
-+NEED_LIBPCI += CONFIG_AST2400
-+endif
-+
- ifeq ($(CONFIG_SATASII), yes)
- FEATURE_CFLAGS += -D'CONFIG_SATASII=1'
- PROGRAMMER_OBJS += satasii.o
-diff --git ./ast1100.c ./ast1100.c
-new file mode 100644
-index 0000000..f661271
---- /dev/null
-+++ ./ast1100.c
-@@ -0,0 +1,421 @@
-+/*
-+ * This file is part of the flashrom project.
-+ *
-+ * Copyright (C) 2017 Raptor Engineering, LLC
-+ *
-+ * 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_ASPEED		0x1a03
-+
-+#define ASPEED_MEMMAP_SIZE		(128 * 1024)
-+#define ASPEED_P2A_OFFSET		0x10000
-+
-+#define AST1100_SCU_APB_ADDR		0x1e6e2000
-+#define AST1100_SCU_APB_BRIDGE_OFFSET	(AST1100_SCU_APB_ADDR & 0xffff)
-+#define AST1100_SCU_PROT_KEY		0x00
-+#define AST1100_SCU_HW_STRAP		0x70
-+
-+#define AST1100_SCU_PASSWORD		0x1688a8a8
-+#define AST1100_SCU_BOOT_SRC_MASK	0x3
-+#define AST1100_SCU_BOOT_SPI		0x2
-+#define AST1100_SCU_BOOT_NONE		0x3
-+
-+#define AST1100_SMC_APB_ADDR		0x16000000
-+#define AST1100_SMC_SMC00		0x00
-+#define AST1100_SMC_CE_CTL(N)		(0x4 + (N * 4))
-+
-+#define AST1100_SMC_SEGMENT_SIZE_MASK	0x3
-+#define AST1100_SMC_SEGMENT_SIZE_32M	0x0
-+#define AST1100_SMC_SEGMENT_SIZE_16M	0x1
-+#define AST1100_SMC_SEGMENT_SIZE_8M	0x2
-+#define AST1100_SMC_SEGMENT_SIZE_4M	0x3
-+
-+#define AST1100_SMC_FLASH_MMIO_ADDR	0x10000000
-+
-+#define AST1100_SPI_CMD_FAST_R_MODE	0x1
-+#define AST1100_SPI_CMD_USER_MODE	0x3
-+#define AST1100_SPI_CMD_MASK		0x3
-+#define AST1100_SPI_STOP_CE_ACTIVE	(0x1 << 2)
-+#define AST1100_SPI_SPEED_SHIFT		8
-+#define AST1100_SPI_SPEED_MASK		(0x7 << AST1100_SPI_SPEED_SHIFT)
-+
-+#define AST1100_SPI_FLASH_MMIO_ADDR	0x30000000
-+
-+#define AST1100_WDT_APB_ADDR		0x1e785000
-+#define AST1100_WDT_APB_BRIDGE_OFFSET	(AST1100_WDT_APB_ADDR & 0xffff)
-+
-+#define AST1100_WDT1_CTR		0x00
-+#define AST1100_WDT1_CTR_RELOAD		0x04
-+#define AST1100_WDT1_CTR_RESTART	0x08
-+#define AST1100_WDT1_CTL		0x0c
-+
-+#define AST1100_WDT_SET_CLOCK		(0x1 << 4)
-+#define AST1100_WDT_RESET_SYSTEM	(0x1 << 1)
-+#define AST1100_WDT_ENABLE		(0x1 << 0)
-+
-+uint8_t *ast1100_device_bar = 0;
-+uint8_t ast1100_device_spi_bus = 0;
-+uint8_t ast1100_device_spi_speed = 0;
-+uint8_t ast1100_device_halt_cpu = 0;
-+uint8_t ast1100_device_reset_cpu = 0;
-+uint8_t ast1100_device_resume_cpu = 0;
-+uint8_t ast1100_device_tickle_fw = 0;
-+uint32_t ast1100_device_flash_mmio_offset = 0;
-+uint32_t ast1100_original_wdt_conf = 0;
-+
-+const struct dev_entry bmc_aspeed_ast1100[] = {
-+	{PCI_VENDOR_ID_ASPEED, 0x2000, OK, "ASPEED", "AST1100" },
-+
-+	{0},
-+};
-+
-+static int ast1100_spi_send_command(struct flashctx *flash,
-+				   unsigned int writecnt, unsigned int readcnt,
-+				   const unsigned char *writearr,
-+				   unsigned char *readarr);
-+
-+static const struct spi_master spi_master_ast1100 = {
-+	.type		= SPI_CONTROLLER_AST1100,
-+	.max_data_read	= 256,
-+	.max_data_write	= 256,
-+	.command	= ast1100_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 int ast1100_set_a2b_bridge_scu(void)
-+{
-+	pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
-+	pci_mmio_writel(AST1100_SCU_APB_ADDR & 0xffff0000, ast1100_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast1100_set_a2b_bridge_wdt(void)
-+{
-+	pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
-+	pci_mmio_writel(AST1100_WDT_APB_ADDR & 0xffff0000, ast1100_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast1100_set_a2b_bridge_smc(void)
-+{
-+	pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
-+	pci_mmio_writel(AST1100_SMC_APB_ADDR, ast1100_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast1100_set_a2b_bridge_smc_flash(void)
-+{
-+	pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
-+	pci_mmio_writel(AST1100_SMC_FLASH_MMIO_ADDR + ast1100_device_flash_mmio_offset, ast1100_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast1100_disable_cpu(void) {
-+	uint32_t dword;
-+
-+	if (ast1100_device_halt_cpu) {
-+		dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
-+		if (((dword & AST1100_SCU_BOOT_SRC_MASK) != AST1100_SCU_BOOT_SPI)
-+			&& ((dword & AST1100_SCU_BOOT_SRC_MASK) != AST1100_SCU_BOOT_NONE)) {	/* NONE permitted to allow for BMC recovery after Ctrl+C or crash */
-+			msg_perr("CPU halt requested but CPU firmware source is not SPI.\n");
-+			pci_mmio_writel(0x0, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_PROT_KEY);
-+			ast1100_device_halt_cpu = 0;
-+			return 1;
-+		}
-+
-+		/* Disable CPU */
-+		ast1100_set_a2b_bridge_scu();
-+		pci_mmio_writel((dword & ~AST1100_SCU_BOOT_SRC_MASK) | AST1100_SCU_BOOT_NONE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
-+		ast1100_original_wdt_conf = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
-+		pci_mmio_writel(ast1100_original_wdt_conf & 0xffff0, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
-+	}
-+
-+	return 0;
-+}
-+
-+static int ast1100_enable_cpu(void) {
-+	uint32_t dword;
-+
-+	if (ast1100_device_halt_cpu && ast1100_device_resume_cpu) {
-+		/* Re-enable CPU */
-+		ast1100_set_a2b_bridge_scu();
-+		dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
-+		pci_mmio_writel((dword & ~AST1100_SCU_BOOT_SRC_MASK) | AST1100_SCU_BOOT_SPI, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
-+	}
-+
-+	return 0;
-+}
-+
-+static int ast1100_reset_cpu(void) {
-+	if (ast1100_device_reset_cpu) {
-+		/* Disable WDT from issuing full SoC reset
-+		 * Without this, OpenPOWER systems will crash when the GPIO blocks are reset on WDT timeout
-+		 */
-+		msg_pinfo("Configuring P2A bridge for WDT access\n");
-+		ast1100_set_a2b_bridge_wdt();
-+		ast1100_original_wdt_conf = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
-+
-+		/* Initiate reset */
-+		msg_pinfo("Setting WDT to reset CPU immediately\n");
-+		pci_mmio_writel(ast1100_original_wdt_conf & 0xffff0, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
-+		pci_mmio_writel(0xec08ce00, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTR_RELOAD);
-+		pci_mmio_writel(0x4755, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTR_RESTART);
-+		pci_mmio_writel(AST1100_WDT_SET_CLOCK, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
-+		pci_mmio_writel(AST1100_WDT_RESET_SYSTEM | AST1100_WDT_ENABLE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
-+	
-+	}
-+
-+	return 0;
-+}
-+
-+static int ast1100_shutdown(void *data) {
-+	/* Reactivate CPU if previously deactivated */
-+	ast1100_enable_cpu();
-+
-+	/* Reset CPU if requested */
-+	ast1100_reset_cpu();
-+
-+	/* Disable backdoor APB access */
-+	pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+int ast1100_init(void)
-+{
-+	struct pci_dev *dev = NULL;
-+	uint32_t dword;
-+
-+	char *arg;
-+
-+	ast1100_device_spi_bus = 0;
-+	arg = extract_programmer_param("spibus");
-+	if (arg)
-+		ast1100_device_spi_bus = strtol(arg, NULL, 0);
-+	free(arg);
-+
-+	ast1100_device_spi_speed = 0;
-+	arg = extract_programmer_param("spispeed");
-+	if (arg)
-+		ast1100_device_spi_speed = strtol(arg, NULL, 0);
-+	free(arg);
-+
-+	ast1100_device_halt_cpu = 0;
-+	arg = extract_programmer_param("cpu");
-+	if (arg && !strcmp(arg,"pause")) {
-+		ast1100_device_halt_cpu = 1;
-+		ast1100_device_resume_cpu = 1;
-+		ast1100_device_reset_cpu = 0;
-+	}
-+	else if (arg && !strcmp(arg,"halt")) {
-+		ast1100_device_halt_cpu = 1;
-+		ast1100_device_resume_cpu = 0;
-+		ast1100_device_reset_cpu = 0;
-+	}
-+	else if (arg && !strcmp(arg,"reset")) {
-+		ast1100_device_halt_cpu = 1;
-+		ast1100_device_resume_cpu = 1;
-+		ast1100_device_reset_cpu = 1;
-+	}
-+	else if (arg) {
-+		msg_perr("Invalid CPU option!  Valid values are: pause | halt | reset\n");
-+		return 1;
-+	}
-+	arg = extract_programmer_param("tickle");
-+	if (arg && !strcmp(arg,"true"))
-+		ast1100_device_tickle_fw = 1;
-+	free(arg);
-+
-+	if ((ast1100_device_spi_bus < 0) || (ast1100_device_spi_bus > 2)) {
-+		msg_perr("SPI bus number out of range!  Valid values are 0 - 2.\n");
-+		return 1;
-+	}
-+
-+	if (rget_io_perms())
-+		return 1;
-+
-+	dev = pcidev_init(bmc_aspeed_ast1100, PCI_BASE_ADDRESS_1);
-+	if (!dev)
-+		return 1;
-+
-+	uintptr_t io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_1);
-+	if (!io_base_addr)
-+		return 1;
-+
-+	msg_pinfo("Detected ASPEED MMIO base address: %p.\n", (void*)io_base_addr);
-+
-+	ast1100_device_bar = rphysmap("ASPEED", io_base_addr, ASPEED_MEMMAP_SIZE);
-+	if (ast1100_device_bar == ERROR_PTR)
-+		return 1;
-+
-+        if (register_shutdown(ast1100_shutdown, dev))
-+                return 1;
-+
-+	io_base_addr += ASPEED_P2A_OFFSET;
-+	msg_pinfo("ASPEED P2A base address: %p.\n", (void*)io_base_addr);
-+
-+	msg_pinfo("Configuring P2A bridge for SCU access\n");
-+	ast1100_set_a2b_bridge_scu();
-+	pci_mmio_writel(AST1100_SCU_PASSWORD, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_PROT_KEY);
-+
-+	/* Halt CPU if requested */
-+	if (ast1100_disable_cpu())
-+		return 1;
-+
-+	msg_pinfo("Configuring P2A bridge for SMC access\n");
-+	ast1100_set_a2b_bridge_smc();
-+
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
-+	if (((dword >> ((ast1100_device_spi_bus * 2) + 4)) & 0x3) != 0x2) {
-+		msg_perr("CE%01x Flash type is not SPI!\n", ast1100_device_spi_bus);
-+		return 1;
-+	}
-+
-+	msg_pinfo("Setting CE%01x SPI relative clock speed to %d\n", ast1100_device_spi_bus, ast1100_device_spi_speed);
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+	dword &= ~AST1100_SPI_SPEED_MASK;
-+	pci_mmio_writel(dword | ((ast1100_device_spi_speed << AST1100_SPI_SPEED_SHIFT) & AST1100_SPI_SPEED_MASK), ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+
-+	msg_pinfo("Enabling CE%01x write\n", ast1100_device_spi_bus);
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
-+	pci_mmio_writel(dword | (0x1 << (10 + ast1100_device_spi_bus)), ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
-+
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
-+	dword &= AST1100_SMC_SEGMENT_SIZE_MASK;
-+	switch (dword & AST1100_SMC_SEGMENT_SIZE_MASK) {
-+		case AST1100_SMC_SEGMENT_SIZE_32M:
-+			ast1100_device_flash_mmio_offset = 0x2000000;
-+			break;
-+		case AST1100_SMC_SEGMENT_SIZE_16M:
-+			ast1100_device_flash_mmio_offset = 0x1000000;
-+			break;
-+		case AST1100_SMC_SEGMENT_SIZE_8M:
-+			ast1100_device_flash_mmio_offset = 0x800000;
-+			break;
-+		case AST1100_SMC_SEGMENT_SIZE_4M:
-+			ast1100_device_flash_mmio_offset = 0x400000;
-+			break;
-+		default:
-+			ast1100_device_flash_mmio_offset = 0x2000000;
-+	}
-+	msg_pinfo("Segment size: 0x%08x\n", ast1100_device_flash_mmio_offset);
-+
-+	ast1100_device_flash_mmio_offset = ast1100_device_flash_mmio_offset * ast1100_device_spi_bus;
-+	msg_pinfo("Using CE%01x offset 0x%08x\n", ast1100_device_spi_bus, ast1100_device_flash_mmio_offset);
-+
-+	register_spi_master(&spi_master_ast1100);
-+
-+	return 0;
-+}
-+
-+static void ast1100_spi_xfer_data(struct flashctx *flash,
-+				   unsigned int writecnt, unsigned int readcnt,
-+				   const unsigned char *writearr,
-+				   unsigned char *readarr)
-+{
-+	int i;
-+	uint32_t dword;
-+
-+	for (i = 0; i < writecnt; i++)
-+		msg_pspew("[%02x]", writearr[i]);
-+	msg_pspew("\n");
-+
-+	for (i = 0; i < writecnt; i=i+4) {
-+		if ((writecnt - i) < 4)
-+			break;
-+		dword = writearr[i];
-+		dword |= writearr[i + 1] << 8;
-+		dword |= writearr[i + 2] << 16;
-+		dword |= writearr[i + 3] << 24;
-+		pci_mmio_writel(dword, ast1100_device_bar + ASPEED_P2A_OFFSET);
-+	}
-+	for (; i < writecnt; i++)
-+		pci_mmio_writeb(writearr[i], ast1100_device_bar + ASPEED_P2A_OFFSET);
-+	programmer_delay(1);
-+	for (i = 0; i < readcnt;) {
-+		dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET);
-+		if (i < readcnt)
-+			readarr[i] = dword & 0xff;
-+		i++;
-+		if (i < readcnt)
-+			readarr[i] = (dword >> 8) & 0xff;
-+		i++;
-+		if (i < readcnt)
-+			readarr[i] = (dword >> 16) & 0xff;
-+		i++;
-+		if (i < readcnt)
-+			readarr[i] = (dword >> 24) & 0xff;
-+		i++;
-+	}
-+
-+	for (i = 0; i < readcnt; i++)
-+		msg_pspew("[%02x]", readarr[i]);
-+	msg_pspew("\n");
-+}
-+
-+/* Returns 0 upon success, a negative number upon errors. */
-+static int ast1100_spi_send_command(struct flashctx *flash,
-+				   unsigned int writecnt, unsigned int readcnt,
-+				   const unsigned char *writearr,
-+				   unsigned char *readarr)
-+{
-+	uint32_t dword;
-+
-+	msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, *writearr, writecnt, readcnt);
-+
-+	/* Set up user command mode */
-+	ast1100_set_a2b_bridge_smc();
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+	pci_mmio_writel(dword | AST1100_SPI_CMD_USER_MODE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+	pci_mmio_writel(dword & ~AST1100_SPI_STOP_CE_ACTIVE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+
-+	/* Transfer data */
-+	ast1100_set_a2b_bridge_smc_flash();
-+	ast1100_spi_xfer_data(flash, writecnt, readcnt, writearr, readarr);
-+
-+	/* Tear down user command mode */
-+	ast1100_set_a2b_bridge_smc();
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+	pci_mmio_writel(dword | AST1100_SPI_STOP_CE_ACTIVE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+	dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+	pci_mmio_writel((dword & ~AST1100_SPI_CMD_MASK) | AST1100_SPI_CMD_FAST_R_MODE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
-+
-+	if (ast1100_device_tickle_fw) {
-+		ast1100_enable_cpu();
-+		programmer_delay(100);
-+		ast1100_disable_cpu();
-+	}
-+
-+	return 0;
-+}
-diff --git ./ast2400.c ./ast2400.c
-new file mode 100644
-index 0000000..01cee76
---- /dev/null
-+++ ./ast2400.c
-@@ -0,0 +1,426 @@
-+/*
-+ * This file is part of the flashrom project.
-+ *
-+ * Copyright (C) 2016 - 2017 Raptor Engineering, LLC
-+ *
-+ * 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_ASPEED		0x1a03
-+
-+#define ASPEED_MEMMAP_SIZE		(128 * 1024)
-+#define ASPEED_P2A_OFFSET		0x10000
-+
-+#define AST2400_SCU_APB_ADDR		0x1e6e2000
-+#define AST2400_SCU_APB_BRIDGE_OFFSET	(AST2400_SCU_APB_ADDR & 0xffff)
-+#define AST2400_SCU_PROT_KEY		0x00
-+#define AST2400_SCU_MISC_CTL		0x2c
-+#define AST2400_SCU_HW_STRAP		0x70
-+
-+#define AST2400_SCU_PASSWORD		0x1688a8a8
-+#define AST2400_SCU_BOOT_SRC_MASK	0x3
-+#define AST2400_SCU_BOOT_SPI		0x2
-+#define AST2400_SCU_BOOT_NONE		0x3
-+
-+#define AST2400_SMC_APB_ADDR		0x1e620000
-+#define AST2400_SMC_FMC00		0x00
-+#define AST2400_SMC_CE_CTL(N)		(0x10 + (N * 4))
-+#define AST2400_SMC_CE_SEG(N)		(0x30 + (N * 4))
-+
-+#define AST2400_SMC_FLASH_MMIO_ADDR	0x20000000
-+
-+#define AST2400_SPI_APB_ADDR		0x1e630000
-+#define AST2400_SPI_CFG			0x00
-+#define AST2400_SPI_CTL			0x04
-+
-+#define AST2400_SPI_CFG_WRITE_EN	0x1
-+#define AST2400_SPI_CMD_FAST_R_MODE	0x1
-+#define AST2400_SPI_CMD_USER_MODE	0x3
-+#define AST2400_SPI_CMD_MASK		0x3
-+#define AST2400_SPI_STOP_CE_ACTIVE	(0x1 << 2)
-+#define AST2400_SPI_CPOL_1		(0x1 << 4)
-+#define AST2400_SPI_LSB_FIRST_CTRL	(0x1 << 5)
-+#define AST2400_SPI_SPEED_MASK		(0xf << 8)
-+#define AST2400_SPI_IO_MODE_MASK	(0x3 << 28)
-+
-+#define AST2400_SPI_FLASH_MMIO_ADDR	0x30000000
-+
-+#define AST2400_WDT_APB_ADDR		0x1e785000
-+#define AST2400_WDT_APB_BRIDGE_OFFSET	(AST2400_WDT_APB_ADDR & 0xffff)
-+
-+#define AST2400_WDT1_CTL		0x0c
-+
-+#define AST2400_WDT_RESET_MODE_MASK	(0x3 << 5)
-+#define AST2400_WDT_RESET_CPU_ONLY	(0x2 << 5)
-+
-+uint8_t *ast2400_device_bar = 0;
-+uint8_t ast2400_device_spi_bus = 0;
-+uint8_t ast2400_device_halt_cpu = 0;
-+uint8_t ast2400_device_resume_cpu = 0;
-+uint8_t ast2400_device_tickle_fw = 0;
-+uint32_t ast2400_device_flash_mmio_offset = 0;
-+uint32_t ast2400_device_host_mode = 0;
-+uint32_t ast2400_original_wdt_conf = 0;
-+
-+const struct dev_entry bmc_aspeed_ast2400[] = {
-+	{PCI_VENDOR_ID_ASPEED, 0x2000, OK, "ASPEED", "AST2400" },
-+
-+	{0},
-+};
-+
-+static int ast2400_spi_send_command(struct flashctx *flash,
-+				   unsigned int writecnt, unsigned int readcnt,
-+				   const unsigned char *writearr,
-+				   unsigned char *readarr);
-+
-+static const struct spi_master spi_master_ast2400 = {
-+	.type		= SPI_CONTROLLER_AST2400,
-+	.max_data_read	= 256,
-+	.max_data_write	= 256,
-+	.command	= ast2400_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 int ast2400_set_a2b_bridge_scu(void)
-+{
-+	pci_mmio_writel(0x0, ast2400_device_bar + 0xf000);
-+	pci_mmio_writel(AST2400_SCU_APB_ADDR & 0xffff0000, ast2400_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast2400_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast2400_set_a2b_bridge_wdt(void)
-+{
-+	pci_mmio_writel(0x0, ast2400_device_bar + 0xf000);
-+	pci_mmio_writel(AST2400_WDT_APB_ADDR & 0xffff0000, ast2400_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast2400_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast2400_set_a2b_bridge_smc(void)
-+{
-+	pci_mmio_writel(0x0, ast2400_device_bar + 0xf000);
-+	pci_mmio_writel(AST2400_SMC_APB_ADDR, ast2400_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast2400_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast2400_set_a2b_bridge_spi(void)
-+{
-+	pci_mmio_writel(0x0, ast2400_device_bar + 0xf000);
-+	pci_mmio_writel(AST2400_SPI_APB_ADDR, ast2400_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast2400_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast2400_set_a2b_bridge_smc_flash(void)
-+{
-+	pci_mmio_writel(0x0, ast2400_device_bar + 0xf000);
-+	pci_mmio_writel(AST2400_SMC_FLASH_MMIO_ADDR + ast2400_device_flash_mmio_offset, ast2400_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast2400_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast2400_set_a2b_bridge_spi_flash(void)
-+{
-+	pci_mmio_writel(0x0, ast2400_device_bar + 0xf000);
-+	pci_mmio_writel(AST2400_SPI_FLASH_MMIO_ADDR, ast2400_device_bar + 0xf004);
-+	pci_mmio_writel(0x1, ast2400_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+static int ast2400_disable_cpu(void) {
-+	uint32_t dword;
-+
-+	if (ast2400_device_halt_cpu) {
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_HW_STRAP);
-+		if (((dword & AST2400_SCU_BOOT_SRC_MASK) != AST2400_SCU_BOOT_SPI)
-+			&& ((dword & AST2400_SCU_BOOT_SRC_MASK) != AST2400_SCU_BOOT_NONE)) {	/* NONE permitted to allow for BMC recovery after Ctrl+C or crash */
-+			msg_perr("CPU halt requested but CPU firmware source is not SPI.\n");
-+			pci_mmio_writel(0x0, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_PROT_KEY);
-+			ast2400_device_halt_cpu = 0;
-+			return 1;
-+		}
-+
-+		/* Disable WDT from issuing full SoC reset
-+		 * Without this, OpenPOWER systems will crash when the GPIO blocks are reset on WDT timeout
-+		 */
-+		msg_pinfo("Configuring P2A bridge for WDT access\n");
-+		ast2400_set_a2b_bridge_wdt();
-+		ast2400_original_wdt_conf = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_WDT_APB_BRIDGE_OFFSET + AST2400_WDT1_CTL);
-+		pci_mmio_writel((ast2400_original_wdt_conf & ~AST2400_WDT_RESET_MODE_MASK) | AST2400_WDT_RESET_CPU_ONLY, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_WDT_APB_BRIDGE_OFFSET + AST2400_WDT1_CTL);
-+
-+		/* Disable CPU */
-+		ast2400_set_a2b_bridge_scu();
-+		pci_mmio_writel((dword & ~AST2400_SCU_BOOT_SRC_MASK) | AST2400_SCU_BOOT_NONE, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_HW_STRAP);
-+	}
-+
-+	return 0;
-+}
-+
-+static int ast2400_enable_cpu(void) {
-+	uint32_t dword;
-+
-+	if (ast2400_device_halt_cpu && ast2400_device_resume_cpu) {
-+		/* Re-enable CPU */
-+		ast2400_set_a2b_bridge_scu();
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_HW_STRAP);
-+		pci_mmio_writel((dword & ~AST2400_SCU_BOOT_SRC_MASK) | AST2400_SCU_BOOT_SPI, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_HW_STRAP);
-+
-+		/* Reset WDT configuration */
-+		ast2400_set_a2b_bridge_wdt();
-+		pci_mmio_writel((ast2400_original_wdt_conf & ~AST2400_WDT_RESET_MODE_MASK) | AST2400_WDT_RESET_CPU_ONLY, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_WDT_APB_BRIDGE_OFFSET + AST2400_WDT1_CTL);
-+	}
-+
-+	return 0;
-+}
-+
-+static int ast2400_shutdown(void *data) {
-+	/* Reactivate CPU if previously deactivated */
-+	ast2400_enable_cpu();
-+
-+	/* Disable backdoor APB access */
-+	pci_mmio_writel(0x0, ast2400_device_bar + 0xf000);
-+
-+	return 0;
-+}
-+
-+int ast2400_init(void)
-+{
-+	struct pci_dev *dev = NULL;
-+	uint32_t dword;
-+	uint8_t divisor;
-+
-+	char *arg;
-+
-+	ast2400_device_spi_bus = 0;
-+	arg = extract_programmer_param("spibus");
-+	if (arg) {
-+		if (!strcmp(arg,"host"))
-+			ast2400_device_host_mode = 1;
-+		else
-+			ast2400_device_spi_bus = strtol(arg, NULL, 0);
-+	}
-+	free(arg);
-+
-+	ast2400_device_halt_cpu = 0;
-+	arg = extract_programmer_param("cpu");
-+	if (arg && !strcmp(arg,"pause")) {
-+		ast2400_device_halt_cpu = 1;
-+		ast2400_device_resume_cpu = 1;
-+	}
-+	if (arg && !strcmp(arg,"halt")) {
-+		ast2400_device_halt_cpu = 1;
-+		ast2400_device_resume_cpu = 0;
-+	}
-+	arg = extract_programmer_param("tickle");
-+	if (arg && !strcmp(arg,"true"))
-+		ast2400_device_tickle_fw = 1;
-+	free(arg);
-+
-+	if ((ast2400_device_host_mode == 0) && ((ast2400_device_spi_bus < 0) || (ast2400_device_spi_bus > 4))) {
-+		msg_perr("SPI bus number out of range!  Valid values are 0 - 4.\n");
-+		return 1;
-+	}
-+
-+	if (rget_io_perms())
-+		return 1;
-+
-+	dev = pcidev_init(bmc_aspeed_ast2400, PCI_BASE_ADDRESS_1);
-+	if (!dev)
-+		return 1;
-+
-+	uintptr_t io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_1);
-+	if (!io_base_addr)
-+		return 1;
-+
-+	msg_pinfo("Detected ASPEED MMIO base address: %p.\n", (void*)io_base_addr);
-+
-+	ast2400_device_bar = rphysmap("ASPEED", io_base_addr, ASPEED_MEMMAP_SIZE);
-+	if (ast2400_device_bar == ERROR_PTR)
-+		return 1;
-+
-+        if (register_shutdown(ast2400_shutdown, dev))
-+                return 1;
-+
-+	io_base_addr += ASPEED_P2A_OFFSET;
-+	msg_pinfo("ASPEED P2A base address: %p.\n", (void*)io_base_addr);
-+
-+	msg_pinfo("Configuring P2A bridge for SCU access\n");
-+	ast2400_set_a2b_bridge_scu();
-+	pci_mmio_writel(AST2400_SCU_PASSWORD, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_PROT_KEY);
-+
-+	dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_MISC_CTL);
-+	pci_mmio_writel(dword & ~((0x1 << 24) | (0x2 << 22)), ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SCU_APB_BRIDGE_OFFSET + AST2400_SCU_MISC_CTL);
-+
-+	/* Halt CPU if requested */
-+	if (ast2400_disable_cpu())
-+		return 1;
-+
-+	msg_pinfo("Configuring P2A bridge for SMC access\n");
-+	ast2400_set_a2b_bridge_smc();
-+
-+	if (ast2400_device_host_mode) {
-+		msg_pinfo("Configuring P2A bridge for SPI access\n");
-+		ast2400_set_a2b_bridge_spi();
-+
-+		divisor = 0;	/* Slowest speed for now */
-+
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CTL);
-+		dword &= ~AST2400_SPI_SPEED_MASK;
-+		dword |= (divisor << 8);
-+		dword &= ~AST2400_SPI_CPOL_1;
-+		dword &= ~AST2400_SPI_LSB_FIRST_CTRL;	/* MSB first */
-+		dword &= ~AST2400_SPI_IO_MODE_MASK;	/* Single bit I/O mode */
-+		pci_mmio_writel(dword, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CTL);
-+	}
-+	else {
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_FMC00);
-+		if (((dword >> (ast2400_device_spi_bus * 2)) & 0x3) != 0x2) {
-+			msg_perr("CE%01x Flash type is not SPI!\n", ast2400_device_spi_bus);
-+			return 1;
-+		}
-+
-+		msg_pinfo("Enabling CE%01x write\n", ast2400_device_spi_bus);
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_FMC00);
-+		pci_mmio_writel(dword | (0x1 << (16 + ast2400_device_spi_bus)), ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_FMC00);
-+
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_SEG(ast2400_device_spi_bus));
-+		ast2400_device_flash_mmio_offset = ((dword >> 16) & 0x3f) * 0x800000;
-+		msg_pinfo("Using CE%01x offset 0x%08x\n", ast2400_device_spi_bus, ast2400_device_flash_mmio_offset);
-+	}
-+
-+	register_spi_master(&spi_master_ast2400);
-+
-+	return 0;
-+}
-+
-+static void ast2400_spi_xfer_data(struct flashctx *flash,
-+				   unsigned int writecnt, unsigned int readcnt,
-+				   const unsigned char *writearr,
-+				   unsigned char *readarr)
-+{
-+	int i;
-+	uint32_t dword;
-+
-+	for (i = 0; i < writecnt; i++)
-+		msg_pspew("[%02x]", writearr[i]);
-+	msg_pspew("\n");
-+
-+	for (i = 0; i < writecnt; i=i+4) {
-+		if ((writecnt - i) < 4)
-+			break;
-+		dword = writearr[i];
-+		dword |= writearr[i + 1] << 8;
-+		dword |= writearr[i + 2] << 16;
-+		dword |= writearr[i + 3] << 24;
-+		pci_mmio_writel(dword, ast2400_device_bar + ASPEED_P2A_OFFSET);
-+	}
-+	for (; i < writecnt; i++)
-+		pci_mmio_writeb(writearr[i], ast2400_device_bar + ASPEED_P2A_OFFSET);
-+	programmer_delay(1);
-+	for (i = 0; i < readcnt;) {
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET);
-+		if (i < readcnt)
-+			readarr[i] = dword & 0xff;
-+		i++;
-+		if (i < readcnt)
-+			readarr[i] = (dword >> 8) & 0xff;
-+		i++;
-+		if (i < readcnt)
-+			readarr[i] = (dword >> 16) & 0xff;
-+		i++;
-+		if (i < readcnt)
-+			readarr[i] = (dword >> 24) & 0xff;
-+		i++;
-+	}
-+
-+	for (i = 0; i < readcnt; i++)
-+		msg_pspew("[%02x]", readarr[i]);
-+	msg_pspew("\n");
-+}
-+
-+/* Returns 0 upon success, a negative number upon errors. */
-+static int ast2400_spi_send_command(struct flashctx *flash,
-+				   unsigned int writecnt, unsigned int readcnt,
-+				   const unsigned char *writearr,
-+				   unsigned char *readarr)
-+{
-+	uint32_t dword;
-+
-+	msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, *writearr, writecnt, readcnt);
-+
-+	if (ast2400_device_host_mode) {
-+		/* Set up user command mode */
-+		ast2400_set_a2b_bridge_spi();
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CFG);
-+		pci_mmio_writel(dword | AST2400_SPI_CFG_WRITE_EN, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CFG);
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CTL);
-+		pci_mmio_writel(dword | AST2400_SPI_CMD_USER_MODE, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CTL);
-+
-+	        /* Transfer data */
-+		ast2400_set_a2b_bridge_spi_flash();
-+		ast2400_spi_xfer_data(flash, writecnt, readcnt, writearr, readarr);
-+
-+		/* Tear down user command mode */
-+		ast2400_set_a2b_bridge_spi();
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CTL);
-+		pci_mmio_writel((dword & ~AST2400_SPI_CMD_MASK) | AST2400_SPI_CMD_FAST_R_MODE, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CTL);
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CFG);
-+		pci_mmio_writel(dword & ~AST2400_SPI_CFG_WRITE_EN, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SPI_CFG);
-+	}
-+	else {
-+		/* Set up user command mode */
-+		ast2400_set_a2b_bridge_smc();
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+		pci_mmio_writel(dword | AST2400_SPI_CMD_USER_MODE, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+		pci_mmio_writel(dword & ~AST2400_SPI_STOP_CE_ACTIVE, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+
-+		/* Transfer data */
-+		ast2400_set_a2b_bridge_smc_flash();
-+		ast2400_spi_xfer_data(flash, writecnt, readcnt, writearr, readarr);
-+
-+		/* Tear down user command mode */
-+		ast2400_set_a2b_bridge_smc();
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+		pci_mmio_writel(dword | AST2400_SPI_STOP_CE_ACTIVE, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+		dword = pci_mmio_readl(ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+		pci_mmio_writel((dword & ~AST2400_SPI_CMD_MASK) | AST2400_SPI_CMD_FAST_R_MODE, ast2400_device_bar + ASPEED_P2A_OFFSET + AST2400_SMC_CE_CTL(ast2400_device_spi_bus));
-+	}
-+
-+	if (ast2400_device_tickle_fw) {
-+		ast2400_enable_cpu();
-+		programmer_delay(100);
-+		ast2400_disable_cpu();
-+	}
-+
-+	return 0;
-+}
-diff --git ./board_enable.c ./board_enable.c
-index 2f0c1c0..758aaf4 100644
---- ./board_enable.c
-+++ ./board_enable.c
-@@ -2433,6 +2433,7 @@ const struct board_match board_matches[] = {
- 	{0x8086, 0x27a0, 0x17aa, 0x2017,  0x8086, 0x27b9, 0x17aa, 0x2009, "^ThinkPad T60", NULL, NULL,        P2, "IBM/Lenovo",  "ThinkPad T60(s)",       0,   OK, p2_whitelist_laptop},
- 	{0x8086, 0x2917, 0x17AA, 0x20F5,  0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad X200", NULL, NULL,       P2, "IBM/Lenovo",  "ThinkPad X200",         0,   OK, p2_whitelist_laptop},
- 	{0x8086, 0x3B07, 0x17AA, 0x2166,  0x8086, 0x3B30, 0x17AA, 0x2167, "^Lenovo X201", NULL, NULL,         P2, "IBM/Lenovo",  "ThinkPad X201",         0,   OK, p2_whitelist_laptop},
-+	{0x8086, 0x1C22, 0x17AA, 0x21DB,  0x8086, 0x1C4F, 0x17AA, 0x21DB, "^ThinkPad X220", NULL, NULL,       P2, "IBM/Lenovo",  "ThinkPad X220",         0,   OK, p2_whitelist_laptop},
- 	{0x8086, 0x1E22, 0x17AA, 0x21FA,  0x8086, 0x1E55, 0x17AA, 0x21FA, "^ThinkPad X230", NULL, NULL,       P2, "IBM/Lenovo",  "ThinkPad X230",         0,   OK, p2_whitelist_laptop},
- 	{0x8086, 0x27A0, 0x17AA, 0x2017,  0x8086, 0x27B9, 0x17AA, 0x2009, "^ThinkPad X60", NULL, NULL,        P2, "IBM/Lenovo",  "ThinkPad X60(s)",       0,   OK, p2_whitelist_laptop},
- 	{0x8086, 0x2411, 0x8086, 0x2411,  0x8086, 0x7125, 0x0e11, 0xb165, NULL,         NULL, NULL,           P3, "Mitac",       "6513WU",                0,   OK, board_mitac_6513wu},
-diff --git ./chipdrivers.h ./chipdrivers.h
-index c85eac9..20529d5 100644
---- ./chipdrivers.h
-+++ ./chipdrivers.h
-@@ -195,4 +195,26 @@ int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int
- int probe_en29lv640b(struct flashctx *flash);
- int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
- 
-+/* spi4ba.c */
-+int spi_enter_4ba_b7(struct flashctx *flash);
-+int spi_enter_4ba_b7_we(struct flashctx *flash);
-+int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
-+int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
-+int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
-+int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t databyte);
-+int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
-+int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
-+int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_52_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_d8_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_byte_program_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t databyte);
-+int spi_nbyte_program_4ba_direct(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
-+int spi_nbyte_read_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
-+int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+
- #endif /* !__CHIPDRIVERS_H__ */
-diff --git ./cli_output.c ./cli_output.c
-index feafbd2..cb82fa1 100644
---- ./cli_output.c
-+++ ./cli_output.c
-@@ -90,7 +90,8 @@ int print(enum msglevel level, const char *fmt, ...)
- 			fflush(output_type);
- 	}
- #ifndef STANDALONE
--	if ((level <= verbose_logfile) && logfile) {
-+	/* skip of msgs starting from '\b' added to skip progress percents */
-+	if ((level <= verbose_logfile) && logfile && (!fmt || fmt[0] != '\b')) {
- 		va_start(ap, fmt);
- 		ret = vfprintf(logfile, fmt, ap);
- 		va_end(ap);
-diff --git ./flash.h ./flash.h
-index da049d1..0b72439 100644
---- ./flash.h
-+++ ./flash.h
-@@ -123,6 +123,14 @@ enum write_granularity {
- #define FEATURE_WRSR_EITHER	(FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
- #define FEATURE_OTP		(1 << 8)
- #define FEATURE_QPI		(1 << 9)
-+/* Feature bits used for 4-bytes addressing mode */
-+#define FEATURE_4BA_SUPPORT		(1 << 10)
-+#define FEATURE_4BA_ONLY 		(1 << 11)
-+#define FEATURE_4BA_EXTENDED_ADDR_REG	(1 << 12)
-+#define FEATURE_4BA_DIRECT_READ		(1 << 13)
-+#define FEATURE_4BA_DIRECT_WRITE	(1 << 14)
-+#define FEATURE_4BA_ALL_ERASERS_DIRECT  (1 << 15)
-+#define FEATURE_4BA_ALL_DIRECT  (FEATURE_4BA_DIRECT_READ | FEATURE_4BA_DIRECT_WRITE | FEATURE_4BA_ALL_ERASERS_DIRECT)
- 
- enum test_state {
- 	OK = 0,
-@@ -167,6 +175,14 @@ struct flashchip {
- 	unsigned int page_size;
- 	int feature_bits;
- 
-+	/* set of function pointers to use in 4-bytes addressing mode */
-+	struct four_bytes_addr_funcs_set {
-+		int (*enter_4ba) (struct flashctx *flash);
-+		int (*read_nbyte) (struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
-+		int (*program_byte) (struct flashctx *flash, unsigned int addr, const uint8_t databyte);
-+		int (*program_nbyte) (struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
-+	} four_bytes_addr_funcs;
-+
- 	/* Indicate how well flashrom supports different operations of this flash chip. */
- 	struct tested {
- 		enum test_state probe;
-@@ -344,6 +360,11 @@ __attribute__((format(printf, 2, 3)));
- #define msg_pspew(...)	print(MSG_SPEW, __VA_ARGS__)	/* programmer debug spew  */
- #define msg_cspew(...)	print(MSG_SPEW, __VA_ARGS__)	/* chip debug spew  */
- 
-+/* Read progress will be shown for reads more than 256KB */
-+#define MIN_LENGTH_TO_SHOW_READ_PROGRESS 256 * 1024
-+/* Read progress will be shown for erases and writes more than 64KB */
-+#define MIN_LENGTH_TO_SHOW_ERASE_AND_WRITE_PROGRESS 64 * 1024
-+
- /* layout.c */
- int register_include_arg(char *name);
- int process_include_args(void);
-diff --git ./flashchips.c ./flashchips.c
-index 40b6b8e..60baa73 100644
---- ./flashchips.c
-+++ ./flashchips.c
-@@ -8045,6 +8045,100 @@ const struct flashchip flashchips[] = {
- 
- 	{
- 		.vendor		= "Macronix",
-+		.name		= "MX25L25635F/MX25L25645E/MX25L25665E",
-+		.bustype	= BUS_SPI,
-+		.manufacture_id	= MACRONIX_ID,
-+		.model_id	= MACRONIX_MX25L25635F,
-+		.total_size	= 32768,
-+		.page_size	= 256,
-+		/* OTP: 512B total; enter 0xB1, exit 0xC1 */
-+		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_SUPPORT,
-+		.four_bytes_addr_funcs =
-+		{
-+			.enter_4ba = spi_enter_4ba_b7, /* enter 4-bytes addressing mode by CMD B7 */
-+			.read_nbyte = spi_nbyte_read_4ba,  /* read from 4-bytes addressing mode */
-+			.program_byte = spi_byte_program_4ba, /* write from 4-bytes addressing mode */
-+			.program_nbyte = spi_nbyte_program_4ba /* write from 4-bytes addressing mode */
-+		},
-+		.tested		= TEST_OK_PREW,
-+		.probe		= probe_spi_rdid,
-+		.probe_timing	= TIMING_ZERO,
-+		.block_erasers	=
-+		{
-+			{
-+				.eraseblocks = { {4 * 1024, 8192} },
-+				.block_erase = spi_block_erase_20_4ba,
-+			}, {
-+				.eraseblocks = { {32 * 1024, 1024} },
-+				.block_erase = spi_block_erase_52_4ba,
-+			}, {
-+				.eraseblocks = { {64 * 1024, 512} },
-+				.block_erase = spi_block_erase_d8_4ba,
-+			}, {
-+				.eraseblocks = { {32 * 1024 * 1024, 1} },
-+				.block_erase = spi_block_erase_60,
-+			}, {
-+				.eraseblocks = { {32 * 1024 * 1024, 1} },
-+				.block_erase = spi_block_erase_c7,
-+			}
-+		},
-+		/* TODO: security register and SBLK/SBULK; MX25L12835F: configuration register */
-+		.printlock	= spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
-+		.unlock		= spi_disable_blockprotect_bp3_srwd,
-+		.write		= spi_chip_write_256,
-+		.read		= spi_chip_read, /* Fast read (0x0B) supported */
-+		.voltage	= {2700, 3600},
-+	},
-+
-+	{
-+		.vendor		= "Macronix",
-+		.name		= "MX66L51235F",
-+		.bustype	= BUS_SPI,
-+		.manufacture_id	= MACRONIX_ID,
-+		.model_id	= MACRONIX_MX66L51235F,
-+		.total_size	= 65536,
-+		.page_size	= 256,
-+		/* OTP: 512B total; enter 0xB1, exit 0xC1 */
-+		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_SUPPORT,
-+		.four_bytes_addr_funcs =
-+		{
-+			.enter_4ba = spi_enter_4ba_b7, /* enter 4-bytes addressing mode by CMD B7 */
-+			.read_nbyte = spi_nbyte_read_4ba,  /* read from 4-bytes addressing mode */
-+			.program_byte = spi_byte_program_4ba, /* write from 4-bytes addressing mode */
-+			.program_nbyte = spi_nbyte_program_4ba /* write from 4-bytes addressing mode */
-+		},
-+		.tested		= TEST_OK_PREW,
-+		.probe		= probe_spi_rdid,
-+		.probe_timing	= TIMING_ZERO,
-+		.block_erasers	=
-+		{
-+			{
-+				.eraseblocks = { {4 * 1024, 16384} },
-+				.block_erase = spi_block_erase_20_4ba,
-+			}, {
-+				.eraseblocks = { {32 * 1024, 2048} },
-+				.block_erase = spi_block_erase_52_4ba,
-+			}, {
-+				.eraseblocks = { {64 * 1024, 1024} },
-+				.block_erase = spi_block_erase_d8_4ba,
-+			}, {
-+				.eraseblocks = { {64 * 1024 * 1024, 1} },
-+				.block_erase = spi_block_erase_60,
-+			}, {
-+				.eraseblocks = { {64 * 1024 * 1024, 1} },
-+				.block_erase = spi_block_erase_c7,
-+			}
-+		},
-+		/* TODO: security register and SBLK/SBULK; MX25L12835F: configuration register */
-+		.printlock	= spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
-+		.unlock		= spi_disable_blockprotect_bp3_srwd,
-+		.write		= spi_chip_write_256,
-+		.read		= spi_chip_read, /* Fast read (0x0B) supported */
-+		.voltage	= {2700, 3600},
-+	},
-+
-+	{
-+		.vendor		= "Macronix",
- 		.name		= "MX25U1635E",
- 		.bustype	= BUS_SPI,
- 		.manufacture_id	= MACRONIX_ID,
-@@ -11747,7 +11841,7 @@ const struct flashchip flashchips[] = {
- 		.total_size	= 16384,
- 		.page_size	= 256,
- 		.feature_bits	= FEATURE_WRSR_WREN,
--		.tested		= TEST_UNTESTED,
-+		.tested		= TEST_OK_PREW,
- 		.probe		= probe_spi_rdid,
- 		.probe_timing	= TIMING_ZERO,
- 		.block_erasers	= {
-@@ -14588,6 +14682,54 @@ const struct flashchip flashchips[] = {
- 
- 	{
- 		.vendor		= "Winbond",
-+		.name		= "W25Q256.V",
-+		.bustype	= BUS_SPI,
-+		.manufacture_id	= WINBOND_NEX_ID,
-+		.model_id	= WINBOND_NEX_W25Q256_V,
-+		.total_size	= 32768,
-+		.page_size	= 256,
-+		/* supports SFDP */
-+		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
-+		/* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
-+		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_SUPPORT | FEATURE_4BA_DIRECT_READ,
-+		.four_bytes_addr_funcs =
-+		{
-+			.enter_4ba = spi_enter_4ba_b7_we, /* enter 4-bytes addressing mode by CMD B7 + WREN */
-+			.read_nbyte = spi_nbyte_read_4ba_direct, /* read directly from any mode, no need to enter 4ba */
-+			.program_byte = spi_byte_program_4ba, /* write from 4-bytes addressing mode */
-+			.program_nbyte = spi_nbyte_program_4ba /* write from 4-bytes addressing mode */
-+		},
-+		.tested		= TEST_OK_PREW,
-+		.probe		= probe_spi_rdid,
-+		.probe_timing	= TIMING_ZERO,
-+		.block_erasers	=
-+		{
-+			{
-+				.eraseblocks = { {4 * 1024, 8192} },
-+				.block_erase = spi_block_erase_20_4ba, /* erases 4k from 4-bytes addressing mode */
-+			}, {
-+				.eraseblocks = { {32 * 1024, 1024} },
-+				.block_erase = spi_block_erase_52_4ba, /* erases 32k from 4-bytes addressing mode */
-+			}, {
-+				.eraseblocks = { {64 * 1024, 512} },
-+				.block_erase = spi_block_erase_d8_4ba, /* erases 64k from 4-bytes addressing mode */
-+			}, {
-+				.eraseblocks = { {32 * 1024 * 1024, 1} },
-+				.block_erase = spi_block_erase_60,
-+			}, {
-+				.eraseblocks = { {32 * 1024 * 1024, 1} },
-+				.block_erase = spi_block_erase_c7,
-+			}
-+		},
-+		.printlock	= spi_prettyprint_status_register_plain, /* TODO: improve */
-+		.unlock		= spi_disable_blockprotect,
-+		.write		= spi_chip_write_256,
-+		.read		= spi_chip_read,
-+		.voltage	= {2700, 3600},
-+	},
-+
-+	{
-+		.vendor		= "Winbond",
- 		.name		= "W25Q20.W",
- 		.bustype	= BUS_SPI,
- 		.manufacture_id	= WINBOND_NEX_ID,
-diff --git ./flashchips.h ./flashchips.h
-index 9ffb30f..7171a62 100644
---- ./flashchips.h
-+++ ./flashchips.h
-@@ -482,6 +482,7 @@
- #define MACRONIX_MX25L25635F	0x2019	/* Same as MX25L25639F, but the latter seems to not support REMS */
- #define MACRONIX_MX25L1635D	0x2415
- #define MACRONIX_MX25L1635E	0x2515	/* MX25L1635{E} */
-+#define MACRONIX_MX66L51235F	0x201a	/* MX66L51235F */
- #define MACRONIX_MX25U1635E	0x2535
- #define MACRONIX_MX25U3235E	0x2536	/* Same as MX25U6435F */
- #define MACRONIX_MX25U6435E	0x2537	/* Same as MX25U6435F */
-diff --git ./flashrom.c ./flashrom.c
-index 25e53f2..d642de8 100644
---- ./flashrom.c
-+++ ./flashrom.c
-@@ -5,6 +5,7 @@
-  * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
-  * Copyright (C) 2005-2008 coresystems GmbH
-  * Copyright (C) 2008,2009 Carl-Daniel Hailfinger
-+ * Copyright (C) 2016-2017 Raptor Engineering, LLC
-  *
-  * 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
-@@ -134,6 +135,30 @@ const struct programmer_entry programmer_table[] = {
- 	},
- #endif
- 
-+#if CONFIG_AST1100 == 1
-+	{
-+		.name			= "ast1100",
-+		.type			= PCI,
-+		.devs.dev		= bmc_aspeed_ast1100,
-+		.init			= ast1100_init,
-+		.map_flash_region	= fallback_map,
-+		.unmap_flash_region	= fallback_unmap,
-+		.delay			= internal_delay,
-+	},
-+#endif
-+
-+#if CONFIG_AST2400 == 1
-+	{
-+		.name			= "ast2400",
-+		.type			= PCI,
-+		.devs.dev		= bmc_aspeed_ast2400,
-+		.init			= ast2400_init,
-+		.map_flash_region	= fallback_map,
-+		.unmap_flash_region	= fallback_unmap,
-+		.delay			= internal_delay,
-+	},
-+#endif
-+
- #if CONFIG_DRKAISER == 1
- 	{
- 		.name			= "drkaiser",
-@@ -1527,6 +1552,17 @@ static int walk_eraseregions(struct flashctx *flash, int erasefunction,
- 	unsigned int start = 0;
- 	unsigned int len;
- 	struct block_eraser eraser = flash->chip->block_erasers[erasefunction];
-+	int show_progress = 0;
-+	unsigned int percent_last, percent_current;
-+	unsigned long size = flash->chip->total_size * 1024;
-+
-+	/* progress visualizaion init */
-+	if(size >= MIN_LENGTH_TO_SHOW_ERASE_AND_WRITE_PROGRESS) {
-+		msg_cinfo(" "); /* only this space will go to logfile but all strings with \b wont. */
-+		msg_cinfo("\b 0%%");
-+		percent_last = percent_current = 0;
-+		show_progress = 1; /* enable progress visualizaion */
-+	}
- 
- 	for (i = 0; i < NUM_ERASEREGIONS; i++) {
- 		/* count==0 for all automatically initialized array
-@@ -1544,8 +1580,20 @@ static int walk_eraseregions(struct flashctx *flash, int erasefunction,
- 				return 1;
- 			}
- 			start += len;
-+
-+			if(show_progress) {
-+				percent_current = (unsigned int) ((unsigned long long)start * 100 / size);
-+				if(percent_current != percent_last) {
-+					msg_cinfo("\b\b\b%2d%%", percent_current);
-+					percent_last = percent_current;
-+				}
-+			}
- 		}
- 	}
-+
-+	if(show_progress)
-+		msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */
-+
- 	msg_cdbg("\n");
- 	return 0;
- }
-@@ -1801,7 +1849,7 @@ void print_buildinfo(void)
- 
- void print_version(void)
- {
--	msg_ginfo("flashrom v%s", flashrom_version);
-+	msg_ginfo("flashrom %s", flashrom_version);
- 	print_sysinfo();
- 	msg_ginfo("\n");
- }
-@@ -1983,7 +2031,7 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
- 	uint8_t *newcontents;
- 	int ret = 0;
- 	unsigned long size = flash->chip->total_size * 1024;
--	int read_all_first = 1; /* FIXME: Make this configurable. */
-+	int read_all_first = 0; /* FIXME: Make this configurable. */
- 
- 	if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) {
- 		msg_cerr("Aborting.\n");
-@@ -2001,6 +2049,44 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
- 	if (flash->chip->unlock)
- 		flash->chip->unlock(flash);
- 
-+	/* Switching to 4-Bytes Addressing mode if flash chip supports it */
-+	if(flash->chip->feature_bits & FEATURE_4BA_SUPPORT) {
-+		/* Do not switch if chip is already in 4-bytes addressing mode */
-+		if (flash->chip->feature_bits & FEATURE_4BA_ONLY) {
-+			msg_cdbg("Flash chip is already in 4-bytes addressing mode.\n");
-+		}
-+		/* Do not switch to 4-Bytes Addressing mode if using Extended Address Register */
-+		else if(flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) {
-+			msg_cdbg("Using 4-bytes addressing with extended address register.\n");
-+		}
-+		/* Go to 4-Bytes Addressing mode if selected
-+		   operation requires 4-Bytes Addressing mode
-+		   (no need if functions are direct-4BA) */
-+		else if(((read_it || verify_it)
-+			&& (!(flash->chip->feature_bits & FEATURE_4BA_DIRECT_READ)))
-+		   || ((erase_it || write_it)
-+			&& ((flash->chip->feature_bits & FEATURE_4BA_ALL_DIRECT) != FEATURE_4BA_ALL_DIRECT))) {
-+
-+			if (!flash->chip->four_bytes_addr_funcs.enter_4ba) {
-+				msg_cerr("No function for Enter 4-bytes addressing mode for this flash chip.\n"
-+					"Please report to flashrom@flashrom.org\n");
-+				return 1;
-+			}
-+
-+			if(flash->chip->four_bytes_addr_funcs.enter_4ba(flash)) {
-+				msg_cerr("Switching to 4-bytes addressing mode failed!\n");
-+				return 1;
-+			}
-+
-+			msg_cdbg("Switched to 4-bytes addressing mode.\n");
-+		}
-+		/* Do not switch to 4-Bytes Addressing mode if all instructions are direct-4BA
-+		   or if the flash chip is 4-Bytes Addressing Only and always in 4BA-mode */
-+		else {
-+			msg_cdbg2("No need to switch to 4-bytes addressing mode.\n");
-+		}
-+	}
-+
- 	if (read_it) {
- 		return read_flash_to_file(flash, filename);
- 	}
-diff --git ./layout.c ./layout.c
-index f71eeaa..2b8ce3c 100644
---- ./layout.c
-+++ ./layout.c
-@@ -259,6 +259,7 @@ int normalize_romentries(const struct flashctx *flash)
- 
- static int copy_old_content(struct flashctx *flash, int oldcontents_valid, uint8_t *oldcontents, uint8_t *newcontents, unsigned int start, unsigned int size)
- {
-+#if 0
- 	if (!oldcontents_valid) {
- 		/* oldcontents is a zero-filled buffer. By reading the current data into oldcontents here, we
- 		 * avoid a rewrite of identical regions even if an initial full chip read didn't happen. */
-@@ -269,6 +270,7 @@ static int copy_old_content(struct flashctx *flash, int oldcontents_valid, uint8
- 			return 1;
- 		}
- 	}
-+#endif
- 	memcpy(newcontents + start, oldcontents + start, size);
- 	return 0;
- }
-diff --git ./pcidev.c ./pcidev.c
-index 2c78063..34b948b 100644
---- ./pcidev.c
-+++ ./pcidev.c
-@@ -37,11 +37,13 @@ enum pci_bartype {
- 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;
- 
-+#ifndef __PPC64__
-+	uint32_t upperaddr;
-+#endif
- 
- 	headertype = pci_read_byte(dev, PCI_HEADER_TYPE) & 0x7f;
- 	msg_pspew("PCI header type 0x%02x\n", headertype);
-@@ -97,6 +99,12 @@ uintptr_t pcidev_readbar(struct pci_dev *dev, int bar)
- 	switch (bartype) {
- 	case TYPE_MEMBAR:
- 		msg_pdbg("MEM");
-+#ifdef __PPC64__
-+		/* PowerPC is able to translate 32-bit BARs into 64-bit host windows.
-+		 * Use the dev->base_addr[x] mechanism to handle mapping.
-+		 */
-+		addr = dev->base_addr[(bar - 0x10) / 0x4] & PCI_BASE_ADDRESS_MEM_MASK;
-+#else
- 		if (!(supported_cycles & PCI_COMMAND_MEMORY)) {
- 			msg_perr("MEM BAR access requested, but device has MEM space accesses disabled.\n");
- 			/* TODO: Abort here? */
-@@ -122,6 +130,7 @@ uintptr_t pcidev_readbar(struct pci_dev *dev, int bar)
- 			}
- 		}
- 		addr &= PCI_BASE_ADDRESS_MEM_MASK;
-+#endif
- 		break;
- 	case TYPE_IOBAR:
- 		msg_pdbg("I/O\n");
-diff --git ./programmer.h ./programmer.h
-index bd8e98d..754f3cc 100644
---- ./programmer.h
-+++ ./programmer.h
-@@ -5,6 +5,7 @@
-  * Copyright (C) 2000 Ronald G. Minnich <rminnich@gmail.com>
-  * Copyright (C) 2005-2009 coresystems GmbH
-  * Copyright (C) 2006-2009 Carl-Daniel Hailfinger
-+ * Copyright (C) 2016-2017 Raptor Engineering, LLC
-  *
-  * 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
-@@ -45,6 +46,12 @@ enum programmer {
- #if CONFIG_GFXNVIDIA == 1
- 	PROGRAMMER_GFXNVIDIA,
- #endif
-+#if CONFIG_AST1100 == 1
-+	PROGRAMMER_AST1100,
-+#endif
-+#if CONFIG_AST2400 == 1
-+	PROGRAMMER_AST2400,
-+#endif
- #if CONFIG_DRKAISER == 1
- 	PROGRAMMER_DRKAISER,
- #endif
-@@ -399,6 +406,18 @@ int gfxnvidia_init(void);
- extern const struct dev_entry gfx_nvidia[];
- #endif
- 
-+/* ast1100.c */
-+#if CONFIG_AST1100 == 1
-+int ast1100_init(void);
-+extern const struct dev_entry bmc_aspeed_ast1100[];
-+#endif
-+
-+/* ast2400.c */
-+#if CONFIG_AST2400 == 1
-+int ast2400_init(void);
-+extern const struct dev_entry bmc_aspeed_ast2400[];
-+#endif
-+
- /* drkaiser.c */
- #if CONFIG_DRKAISER == 1
- int drkaiser_init(void);
-@@ -600,6 +619,14 @@ enum spi_controller {
- #if CONFIG_CH341A_SPI == 1
- 	SPI_CONTROLLER_CH341A_SPI,
- #endif
-+
-+#if CONFIG_AST1100 == 1
-+	SPI_CONTROLLER_AST1100,
-+#endif
-+
-+#if CONFIG_AST2400 == 1
-+	SPI_CONTROLLER_AST2400,
-+#endif
- };
- 
- #define MAX_DATA_UNSPECIFIED 0
-diff --git ./serprog.c ./serprog.c
-index 98aac83..c9d98bf 100644
---- ./serprog.c
-+++ ./serprog.c
-@@ -945,7 +945,10 @@ static int serprog_spi_read(struct flashctx *flash, uint8_t *buf,
- 	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);
-+		ret = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
-+			? spi_nbyte_read(flash, start + i, buf + i, cur_len)
-+			: flash->chip->four_bytes_addr_funcs.read_nbyte(flash,
-+						 start + i, buf + i, cur_len);
- 		if (ret)
- 			return ret;
- 	}
-diff --git ./spi.c ./spi.c
-index 894f73f..895b6a3 100644
---- ./spi.c
-+++ ./spi.c
-@@ -100,6 +100,20 @@ int default_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned i
- 	return spi_write_chunked(flash, buf, start, len, max_data);
- }
- 
-+static int my_ffs(int x)
-+{
-+	int rc = 0;
-+	while(x)
-+	{
-+		if (x & 1)
-+			return rc;
-+		rc++;
-+		x >>= 1;
-+	}
-+
-+	return 0;
-+}
-+
- int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
- 		  unsigned int len)
- {
-@@ -110,7 +124,10 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
- 	 * means 0xffffff, the highest unsigned 24bit number.
- 	 */
- 	addrbase = spi_get_valid_read_addr(flash);
--	if (addrbase + flash->chip->total_size * 1024 > (1 << 24)) {
-+	/* Show flash chip size warning if flash chip doesn't support
-+	   4-Bytes Addressing mode and last address excedes 24 bits */
-+	if (!(flash->chip->feature_bits & FEATURE_4BA_SUPPORT) &&
-+	    addrbase + flash->chip->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. */
-@@ -119,7 +136,7 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
- 	/* 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->chip->total_size * 1024) > (ffs(addrbase) ? : 33)) {
-+	if (my_ffs(flash->chip->total_size * 1024) > (my_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");
-diff --git ./spi25.c ./spi25.c
-index af4b6db..ae5e51d 100644
---- ./spi25.c
-+++ ./spi25.c
-@@ -28,6 +28,7 @@
- #include "chipdrivers.h"
- #include "programmer.h"
- #include "spi.h"
-+#include "spi4ba.h"
- 
- static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
- {
-@@ -948,6 +949,16 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
- 	int rc = 0;
- 	unsigned int i, j, starthere, lenhere, toread;
- 	unsigned int page_size = flash->chip->page_size;
-+	int show_progress = 0;
-+	unsigned int percent_last, percent_current;
-+
-+	/* progress visualizaion init */
-+	if(len >= MIN_LENGTH_TO_SHOW_READ_PROGRESS) {
-+		msg_cinfo(" "); /* only this space will go to logfile but all strings with \b wont. */
-+		msg_cinfo("\b 0%%");
-+		percent_last = percent_current = 0;
-+		show_progress = 1; /* enable progress visualizaion */
-+	}
- 
- 	/* Warning: This loop has a very unusual condition and body.
- 	 * The loop needs to go through each page with at least one affected
-@@ -966,13 +977,28 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
- 		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);
-+			rc = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
-+				? spi_nbyte_read(flash, starthere + j, buf + starthere - start + j, toread)
-+				: flash->chip->four_bytes_addr_funcs.read_nbyte(flash, starthere + j,
-+					buf + starthere - start + j, toread);
- 			if (rc)
- 				break;
- 		}
- 		if (rc)
- 			break;
-+
-+		if(show_progress) {
-+			percent_current = (unsigned int) ((unsigned long long)(starthere +
-+									lenhere - start) * 100 / len);
-+			if(percent_current != percent_last) {
-+				msg_cinfo("\b\b\b%2d%%", percent_current);
-+				percent_last = percent_current;
- 	}
-+		}
-+	}
-+
-+	if(show_progress && !rc)
-+		msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */
- 
- 	return rc;
- }
-@@ -1011,7 +1037,10 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s
- 		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);
-+			rc = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
-+				? spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite)
-+				: flash->chip->four_bytes_addr_funcs.program_nbyte(flash, starthere + j,
-+					buf + starthere - start + j, towrite);
- 			if (rc)
- 				break;
- 			while (spi_read_status_register(flash) & SPI_SR_WIP)
-@@ -1037,7 +1066,9 @@ int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int st
- 	int result = 0;
- 
- 	for (i = start; i < start + len; i++) {
--		result = spi_byte_program(flash, i, buf[i - start]);
-+		result = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0
-+			? spi_byte_program(flash, i, buf[i - start])
-+			: flash->chip->four_bytes_addr_funcs.program_byte(flash, i, buf[i - start]);
- 		if (result)
- 			return 1;
- 		while (spi_read_status_register(flash) & SPI_SR_WIP)
-diff --git ./spi4ba.c ./spi4ba.c
-new file mode 100644
-index 0000000..6e1cc9b
---- /dev/null
-+++ ./spi4ba.c
-@@ -0,0 +1,920 @@
-+/*
-+ * This file is part of the flashrom project.
-+ *
-+ * Copyright (C) 2014 Boris Baykov
-+ *
-+ * 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
-+ */
-+
-+/*
-+ * SPI chip driver functions for 4-bytes addressing
-+ */
-+
-+#include <string.h>
-+#include "flash.h"
-+#include "chipdrivers.h"
-+#include "spi.h"
-+#include "programmer.h"
-+#include "spi4ba.h"
-+
-+/* #define MSG_TRACE_4BA_FUNCS 1 */
-+
-+#ifdef MSG_TRACE_4BA_FUNCS
-+#define msg_trace(...) print(MSG_DEBUG, __VA_ARGS__)
-+#else
-+#define msg_trace(...)
-+#endif
-+
-+/* Enter 4-bytes addressing mode (without sending WREN before) */
-+int spi_enter_4ba_b7(struct flashctx *flash)
-+{
-+	const unsigned char cmd[JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_ENTER_4_BYTE_ADDR_MODE };
-+
-+	msg_trace("-> %s\n", __func__);
-+
-+	/* Switch to 4-bytes addressing mode  */
-+	return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
-+}
-+
-+/* Enter 4-bytes addressing mode with sending WREN before */
-+int spi_enter_4ba_b7_we(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_ENTER_4_BYTE_ADDR_MODE_OUTSIZE,
-+		.writearr	= (const unsigned char[]){ JEDEC_ENTER_4_BYTE_ADDR_MODE },
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s\n", __func__);
-+
-+	/* Switch to 4-bytes addressing mode  */
-+	result = spi_send_multicommand(flash, cmds);
-+	if (result) {
-+		msg_cerr("%s failed during command execution\n", __func__);
-+	}
-+	return result;
-+}
-+
-+/* Program one flash byte from 4-bytes addressing mode */
-+int spi_byte_program_4ba(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 + 1,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_BYTE_PROGRAM,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff),
-+					databyte
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X)\n", __func__, addr);
-+
-+	result = spi_send_multicommand(flash, cmds);
-+	if (result) {
-+		msg_cerr("%s failed during command execution at address 0x%x\n",
-+			__func__, addr);
-+	}
-+	return result;
-+}
-+
-+/* Program flash bytes from 4-bytes addressing mode */
-+int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr,
-+			  const uint8_t *bytes, unsigned int len)
-+{
-+	int result;
-+	unsigned char cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + 256] = {
-+		JEDEC_BYTE_PROGRAM,
-+		(addr >> 24) & 0xff,
-+		(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) - 1 + len,
-+		.writearr	= cmd,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
-+
-+	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[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1], 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;
-+}
-+
-+/* Read flash bytes from 4-bytes addressing mode */
-+int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr,
-+		   uint8_t *bytes, unsigned int len)
-+{
-+	const unsigned char cmd[JEDEC_READ_OUTSIZE + 1] = {
-+		JEDEC_READ,
-+		(addr >> 24) & 0xff,
-+		(addr >> 16) & 0xff,
-+		(addr >> 8) & 0xff,
-+		(addr >> 0) & 0xff
-+	};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
-+
-+	/* Send Read */
-+	return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
-+}
-+
-+/* Erases 4 KB of flash from 4-bytes addressing mode */
-+int spi_block_erase_20_4ba(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 + 1,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_SE,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff)
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	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;
-+}
-+
-+/* Erases 32 KB of flash from 4-bytes addressing mode */
-+int spi_block_erase_52_4ba(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 + 1,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_BE_52,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff)
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	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;
-+}
-+
-+/* Erases 64 KB of flash from 4-bytes addressing mode */
-+int spi_block_erase_d8_4ba(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 + 1,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_BE_D8,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff)
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	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;
-+}
-+
-+/* Write Extended Address Register value */
-+int spi_write_extended_address_register(struct flashctx *flash, uint8_t regdata)
-+{
-+	int result;
-+	struct spi_command cmds[] = {
-+	{
-+		.writecnt	= JEDEC_WREN_OUTSIZE,
-+		.writearr	= (const unsigned char[]){ JEDEC_WREN },
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= JEDEC_WRITE_EXT_ADDR_REG_OUTSIZE,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_WRITE_EXT_ADDR_REG,
-+					regdata
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (%02X)\n", __func__, regdata);
-+
-+	result = spi_send_multicommand(flash, cmds);
-+	if (result) {
-+		msg_cerr("%s failed during command execution\n", __func__);
-+		return result;
-+	}
-+	return 0;
-+}
-+
-+/* Assign required value of Extended Address Register. This function
-+   keeps last value of the register and writes the register if the
-+   value has to be changed only. */
-+int set_extended_address_register(struct flashctx *flash, uint8_t data)
-+{
-+	static uint8_t ext_addr_reg_state; /* memory for last register state */
-+	static int ext_addr_reg_state_valid = 0;
-+	int result;
-+
-+	if (ext_addr_reg_state_valid == 0 || data != ext_addr_reg_state) {
-+		result = spi_write_extended_address_register(flash, data);
-+		if (result) {
-+			ext_addr_reg_state_valid = 0;
-+			return result;
-+		}
-+		ext_addr_reg_state = data;
-+		ext_addr_reg_state_valid = 1;
-+	}
-+	return 0;
-+}
-+
-+/* Program one flash byte using Extended Address Register
-+   from 3-bytes addressing mode */
-+int spi_byte_program_4ba_ereg(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,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X)\n", __func__, addr);
-+
-+	result = set_extended_address_register(flash, (addr >> 24) & 0xff);
-+	if (result)
-+		return result;
-+
-+	result = spi_send_multicommand(flash, cmds);
-+	if (result) {
-+		msg_cerr("%s failed during command execution at address 0x%x\n",
-+			__func__, addr);
-+	}
-+	return result;
-+}
-+
-+/* Program flash bytes using Extended Address Register
-+   from 3-bytes addressing mode */
-+int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr,
-+				  const uint8_t *bytes, unsigned int len)
-+{
-+	int result;
-+	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,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
-+
-+	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[JEDEC_BYTE_PROGRAM_OUTSIZE - 1], bytes, len);
-+
-+	result = set_extended_address_register(flash, (addr >> 24) & 0xff);
-+	if (result)
-+		return result;
-+
-+	result = spi_send_multicommand(flash, cmds);
-+	if (result) {
-+		msg_cerr("%s failed during command execution at address 0x%x\n",
-+			__func__, addr);
-+	}
-+	return result;
-+}
-+
-+/* Read flash bytes using Extended Address Register
-+   from 3-bytes addressing mode */
-+int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr,
-+		   uint8_t *bytes, unsigned int len)
-+{
-+	int result;
-+	const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
-+		JEDEC_READ,
-+		(addr >> 16) & 0xff,
-+		(addr >> 8) & 0xff,
-+		(addr >> 0) & 0xff
-+	};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
-+
-+	result = set_extended_address_register(flash, (addr >> 24) & 0xff);
-+	if (result)
-+		return result;
-+
-+	/* Send Read */
-+	return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
-+}
-+
-+/* Erases 4 KB of flash using Extended Address Register
-+   from 3-bytes addressing mode */
-+int spi_block_erase_20_4ba_ereg(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,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	result = set_extended_address_register(flash, (addr >> 24) & 0xff);
-+	if (result)
-+		return result;
-+
-+	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;
-+}
-+
-+/* Erases 32 KB of flash using Extended Address Register
-+   from 3-bytes addressing mode */
-+int spi_block_erase_52_4ba_ereg(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,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	result = set_extended_address_register(flash, (addr >> 24) & 0xff);
-+	if (result)
-+		return result;
-+
-+	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;
-+}
-+
-+/* Erases 64 KB of flash using Extended Address Register
-+   from 3-bytes addressing mode */
-+int spi_block_erase_d8_4ba_ereg(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,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	result = set_extended_address_register(flash, (addr >> 24) & 0xff);
-+	if (result)
-+		return result;
-+
-+	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;
-+}
-+
-+/* Program one flash byte with 4-bytes address from ANY mode (3-bytes or 4-bytes)
-+   JEDEC_BYTE_PROGRAM_4BA (12h) instruction is new for 4-bytes addressing flash chips.
-+   The presence of this instruction for an exact chip should be checked
-+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
-+int spi_byte_program_4ba_direct(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_4BA_OUTSIZE,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_BYTE_PROGRAM_4BA,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff),
-+					databyte
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X)\n", __func__, addr);
-+
-+	result = spi_send_multicommand(flash, cmds);
-+	if (result) {
-+		msg_cerr("%s failed during command execution at address 0x%x\n",
-+			__func__, addr);
-+	}
-+	return result;
-+}
-+
-+/* Program flash bytes with 4-bytes address from ANY mode (3-bytes or 4-bytes)
-+   JEDEC_BYTE_PROGRAM_4BA (12h) instruction is new for 4-bytes addressing flash chips.
-+   The presence of this instruction for an exact chip should be checked
-+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
-+int spi_nbyte_program_4ba_direct(struct flashctx *flash, unsigned int addr,
-+				  const uint8_t *bytes, unsigned int len)
-+{
-+	int result;
-+	unsigned char cmd[JEDEC_BYTE_PROGRAM_4BA_OUTSIZE - 1 + 256] = {
-+		JEDEC_BYTE_PROGRAM_4BA,
-+		(addr >> 24) & 0xff,
-+		(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_4BA_OUTSIZE - 1 + len,
-+		.writearr	= cmd,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
-+
-+	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[JEDEC_BYTE_PROGRAM_4BA_OUTSIZE - 1], 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;
-+}
-+
-+/* Read flash bytes with 4-bytes address from ANY mode (3-bytes or 4-bytes)
-+   JEDEC_READ_4BA (13h) instruction is new for 4-bytes addressing flash chips.
-+   The presence of this instruction for an exact chip should be checked
-+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
-+int spi_nbyte_read_4ba_direct(struct flashctx *flash, unsigned int addr,
-+		   uint8_t *bytes, unsigned int len)
-+{
-+	const unsigned char cmd[JEDEC_READ_4BA_OUTSIZE] = {
-+		JEDEC_READ_4BA,
-+		(addr >> 24) & 0xff,
-+		(addr >> 16) & 0xff,
-+		(addr >> 8) & 0xff,
-+		(addr >> 0) & 0xff
-+	};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
-+
-+	/* Send Read */
-+	return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
-+}
-+
-+/* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
-+   JEDEC_SE_4BA (21h) instruction is new for 4-bytes addressing flash chips.
-+   The presence of this instruction for an exact chip should be checked
-+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
-+int spi_block_erase_21_4ba_direct(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_4BA_OUTSIZE,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_SE_4BA,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff)
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	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;
-+}
-+
-+/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
-+   JEDEC_BE_5C_4BA (5Ch) instruction is new for 4-bytes addressing flash chips.
-+   The presence of this instruction for an exact chip should be checked
-+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
-+int spi_block_erase_5c_4ba_direct(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_5C_4BA_OUTSIZE,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_BE_5C_4BA,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff)
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	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;
-+}
-+
-+/* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
-+   JEDEC_BE_DC_4BA (DCh) instruction is new for 4-bytes addressing flash chips.
-+   The presence of this instruction for an exact chip should be checked
-+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
-+int spi_block_erase_dc_4ba_direct(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_DC_4BA_OUTSIZE,
-+		.writearr	= (const unsigned char[]){
-+					JEDEC_BE_DC_4BA,
-+					(addr >> 24) & 0xff,
-+					(addr >> 16) & 0xff,
-+					(addr >> 8) & 0xff,
-+					(addr & 0xff)
-+				},
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}, {
-+		.writecnt	= 0,
-+		.writearr	= NULL,
-+		.readcnt	= 0,
-+		.readarr	= NULL,
-+	}};
-+
-+	msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
-+
-+	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;
-+}
-diff --git ./spi4ba.h ./spi4ba.h
-new file mode 100644
-index 0000000..8e500d1
---- /dev/null
-+++ ./spi4ba.h
-@@ -0,0 +1,114 @@
-+/*
-+ * This file is part of the flashrom project.
-+ *
-+ * Copyright (C) 2014 Boris Baykov
-+ *
-+ * 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
-+*/
-+
-+/*
-+ * JEDEC flash chips instructions for 4-bytes addressing
-+ * SPI chip driver functions for 4-bytes addressing
-+ */
-+
-+#ifndef __SPI_4BA_H__
-+#define __SPI_4BA_H__ 1
-+
-+/* Enter 4-byte Address Mode */
-+#define JEDEC_ENTER_4_BYTE_ADDR_MODE		0xB7
-+#define JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE	0x01
-+#define JEDEC_ENTER_4_BYTE_ADDR_MODE_INSIZE	0x00
-+
-+/* Exit 4-byte Address Mode */
-+#define JEDEC_EXIT_4_BYTE_ADDR_MODE		0xE9
-+#define JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE	0x01
-+#define JEDEC_EXIT_4_BYTE_ADDR_MODE_INSIZE	0x00
-+
-+/* Write Extended Address Register */
-+#define JEDEC_WRITE_EXT_ADDR_REG		0xC5
-+#define JEDEC_WRITE_EXT_ADDR_REG_OUTSIZE	0x02
-+#define JEDEC_WRITE_EXT_ADDR_REG_INSIZE		0x00
-+
-+/* Read Extended Address Register */
-+#define JEDEC_READ_EXT_ADDR_REG			0xC8
-+#define JEDEC_READ_EXT_ADDR_REG_OUTSIZE		0x01
-+#define JEDEC_READ_EXT_ADDR_REG_INSIZE		0x01
-+
-+/* Read the memory with 4-byte address
-+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
-+#define JEDEC_READ_4BA		0x13
-+#define JEDEC_READ_4BA_OUTSIZE	0x05
-+/*      JEDEC_READ_4BA_INSIZE : any length */
-+
-+/* Write memory byte with 4-byte address
-+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
-+#define JEDEC_BYTE_PROGRAM_4BA		0x12
-+#define JEDEC_BYTE_PROGRAM_4BA_OUTSIZE	0x06
-+#define JEDEC_BYTE_PROGRAM_4BA_INSIZE	0x00
-+
-+/* Sector Erase 0x21 (with 4-byte address), usually 4k size.
-+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
-+#define JEDEC_SE_4BA		0x21
-+#define JEDEC_SE_4BA_OUTSIZE	0x05
-+#define JEDEC_SE_4BA_INSIZE	0x00
-+
-+/* Block Erase 0x5C (with 4-byte address), usually 32k size.
-+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
-+#define JEDEC_BE_5C_4BA		0x5C
-+#define JEDEC_BE_5C_4BA_OUTSIZE	0x05
-+#define JEDEC_BE_5C_4BA_INSIZE	0x00
-+
-+/* Block Erase 0xDC (with 4-byte address), usually 64k size.
-+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
-+#define JEDEC_BE_DC_4BA		0xdc
-+#define JEDEC_BE_DC_4BA_OUTSIZE	0x05
-+#define JEDEC_BE_DC_4BA_INSIZE	0x00
-+
-+/* enter 4-bytes addressing mode */
-+int spi_enter_4ba_b7(struct flashctx *flash);
-+int spi_enter_4ba_b7_we(struct flashctx *flash);
-+
-+/* read/write flash bytes in 4-bytes addressing mode */
-+int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
-+int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
-+int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
-+
-+/* erase flash bytes in 4-bytes addressing mode */
-+int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+
-+/* read/write flash bytes from 3-bytes addressing mode using extended address register */
-+int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t databyte);
-+int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
-+int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
-+
-+/* erase flash bytes from 3-bytes addressing mode using extended address register */
-+int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_52_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_d8_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+
-+/* read/write flash bytes with 4-bytes address from any mode (3-byte or 4-byte) */
-+int spi_byte_program_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t databyte);
-+int spi_nbyte_program_4ba_direct(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
-+int spi_nbyte_read_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
-+
-+/* erase flash bytes with 4-bytes address from any mode (3-byte or 4-byte) */
-+int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-+
-+
-+#endif /* __SPI_4BA_H__ */