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__ */