From b29447ef8f93cfe2c91be9a5754ebca31ee9fb5d Mon Sep 17 00:00:00 2001 From: Matt DeVillier Date: Tue, 30 Jul 2019 21:46:34 -0500 Subject: [PATCH] modules/flashrom: update to v1.2 release - Update flashrom module to v1.2. - Drop Thinkpad x220 patch as it's now properly supported. - Drop 'laptop=force_I_want_a_brick' from board FLASHROM_OPTIONS since it's no longer needed. - Migrate kgpe-d16 patch. The kgpe-d16 patch needed a complete overhaul when rebased against flashrom v1.2, and needs close inspection/testing as a result. The following changes were made from the previous patch: - dropped addition of 4-byte addressing (4BA), since now supported - dropped addtiion of Macronix MX25L256 and MX66L512 chips, since now supported - added 4BA erase commands for Winbond W25Q256 chip - dropped code to show progress indicator, since another PR already adds that Signed-off-by: Matt DeVillier --- blobs/x220/readme.md | 2 +- boards/librem13v2/librem13v2.config | 2 +- boards/librem13v4/librem13v4.config | 2 +- boards/librem15v3/librem15v3.config | 2 +- boards/librem15v4/librem15v4.config | 2 +- boards/t420/t420.config | 2 +- boards/x220/x220.config | 2 +- boards/x230-flash/x230-flash.config | 2 +- boards/x230/x230.config | 2 +- modules/flashrom | 4 +- .../flashrom-1.0/0100-enable-kgpe-d16.patch | 2599 ----------------- .../0101-enable-thinkpad-x220.patch | 12 - .../flashrom-v1.2/0100-enable-kgpe-d16.patch | 1097 +++++++ 13 files changed, 1108 insertions(+), 2622 deletions(-) delete mode 100644 patches/flashrom-1.0/0100-enable-kgpe-d16.patch delete mode 100644 patches/flashrom-1.0/0101-enable-thinkpad-x220.patch create mode 100644 patches/flashrom-v1.2/0100-enable-kgpe-d16.patch diff --git a/blobs/x220/readme.md b/blobs/x220/readme.md index ff682f3b..2d2ce210 100644 --- a/blobs/x220/readme.md +++ b/blobs/x220/readme.md @@ -7,7 +7,7 @@ To get the binaries, start with a copy of the original Lenovo firmware image. If you do not have one already, you can read one out from the laptops SPI flash. ``` -flashrom --programmer internal:laptop=force_I_want_a_brick -r original.bin +flashrom --programmer internal -r original.bin ``` Once you have the image, the provided extraction script will extract the files needed. diff --git a/boards/librem13v2/librem13v2.config b/boards/librem13v2/librem13v2.config index 2d3f3aca..776256be 100644 --- a/boards/librem13v2/librem13v2.config +++ b/boards/librem13v2/librem13v2.config @@ -34,4 +34,4 @@ export CONFIG_BOOT_DEV="/dev/nvme0n1p1" export CONFIG_BOOT_GUI_MENU_NAME="Purism Librem 13v2 Heads Boot Menu" export CONFIG_WARNING_BG_COLOR="--background-gradient 0 0 0 150 125 0" export CONFIG_ERROR_BG_COLOR="--background-gradient 0 0 0 150 0 0" -export CONFIG_FLASHROM_OPTIONS="-p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq" +export CONFIG_FLASHROM_OPTIONS="-p internal" diff --git a/boards/librem13v4/librem13v4.config b/boards/librem13v4/librem13v4.config index e1a4bbc0..1b0a83ab 100644 --- a/boards/librem13v4/librem13v4.config +++ b/boards/librem13v4/librem13v4.config @@ -34,4 +34,4 @@ export CONFIG_BOOT_DEV="/dev/nvme0n1p1" export CONFIG_BOOT_GUI_MENU_NAME="Purism Librem 13v2 Heads Boot Menu" export CONFIG_WARNING_BG_COLOR="--background-gradient 0 0 0 150 125 0" export CONFIG_ERROR_BG_COLOR="--background-gradient 0 0 0 150 0 0" -export CONFIG_FLASHROM_OPTIONS="-p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq" +export CONFIG_FLASHROM_OPTIONS="-p internal" diff --git a/boards/librem15v3/librem15v3.config b/boards/librem15v3/librem15v3.config index 2580e15b..c73f5b8f 100644 --- a/boards/librem15v3/librem15v3.config +++ b/boards/librem15v3/librem15v3.config @@ -36,4 +36,4 @@ export CONFIG_BOOT_DEV="/dev/nvme0n1p1" export CONFIG_BOOT_GUI_MENU_NAME="Purism Librem 15v3 Heads Boot Menu" export CONFIG_WARNING_BG_COLOR="--background-gradient 0 0 0 150 125 0" export CONFIG_ERROR_BG_COLOR="--background-gradient 0 0 0 150 0 0" -export CONFIG_FLASHROM_OPTIONS="-p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq" +export CONFIG_FLASHROM_OPTIONS="-p internal" diff --git a/boards/librem15v4/librem15v4.config b/boards/librem15v4/librem15v4.config index 107be032..b2349799 100644 --- a/boards/librem15v4/librem15v4.config +++ b/boards/librem15v4/librem15v4.config @@ -36,4 +36,4 @@ export CONFIG_BOOT_DEV="/dev/nvme0n1p1" export CONFIG_BOOT_GUI_MENU_NAME="Purism Librem 15v4 Heads Boot Menu" export CONFIG_WARNING_BG_COLOR="--background-gradient 0 0 0 150 125 0" export CONFIG_ERROR_BG_COLOR="--background-gradient 0 0 0 150 0 0" -export CONFIG_FLASHROM_OPTIONS="-p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq" +export CONFIG_FLASHROM_OPTIONS="-p internal" diff --git a/boards/t420/t420.config b/boards/t420/t420.config index ea440642..71d769f2 100644 --- a/boards/t420/t420.config +++ b/boards/t420/t420.config @@ -33,4 +33,4 @@ export CONFIG_BOOT_DEV="/dev/sda1" export CONFIG_BOOT_GUI_MENU_NAME="ThinkPad T420 Heads Boot Menu" export CONFIG_WARNING_BG_COLOR="--background-gradient 0 0 0 150 125 0" export CONFIG_ERROR_BG_COLOR="--background-gradient 0 0 0 150 0 0" -export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq --ifd --image bios" +export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios" diff --git a/boards/x220/x220.config b/boards/x220/x220.config index 3af04149..7548b773 100644 --- a/boards/x220/x220.config +++ b/boards/x220/x220.config @@ -33,4 +33,4 @@ export CONFIG_BOOT_DEV="/dev/sda1" export CONFIG_BOOT_GUI_MENU_NAME="ThinkPad X220 Heads Boot Menu" export CONFIG_WARNING_BG_COLOR="--background-gradient 0 0 0 150 125 0" export CONFIG_ERROR_BG_COLOR="--background-gradient 0 0 0 150 0 0" -export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq --ifd --image bios" +export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios" diff --git a/boards/x230-flash/x230-flash.config b/boards/x230-flash/x230-flash.config index 5530ba27..f991b116 100644 --- a/boards/x230-flash/x230-flash.config +++ b/boards/x230-flash/x230-flash.config @@ -16,7 +16,7 @@ CONFIG_LINUX_USB=y CONFIG_LINUX_E1000E=y export CONFIG_BOOTSCRIPT=/bin/x230-flash.init -export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq --ifd --image bios" +export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios" # This board is "special" in that we only want the top 4 MB of the ROM # for flashing into SPI flash 1 on the mainboard. This is enough to diff --git a/boards/x230/x230.config b/boards/x230/x230.config index ad49270e..48a11525 100644 --- a/boards/x230/x230.config +++ b/boards/x230/x230.config @@ -33,7 +33,7 @@ export CONFIG_BOOT_DEV="/dev/sda1" export CONFIG_BOOT_GUI_MENU_NAME="Thinkpad X230 Heads Boot Menu" export CONFIG_WARNING_BG_COLOR="--background-gradient 0 0 0 150 125 0" export CONFIG_ERROR_BG_COLOR="--background-gradient 0 0 0 150 0 0" -export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal:laptop=force_I_want_a_brick,ich_spi_mode=hwseq --ifd --image bios" +export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios" # This board has two SPI flash chips, an 8 MB that holds the IFD, # the ME image and part of the coreboot image, and a 4 MB one that diff --git a/modules/flashrom b/modules/flashrom index 0a29b184..1f6b1566 100644 --- a/modules/flashrom +++ b/modules/flashrom @@ -5,11 +5,11 @@ flashrom_depends := pciutils $(musl_dep) #flashrom_version := git #flashrom_repo := https://github.com/osresearch/flashrom -flashrom_version := 1.0 +flashrom_version := v1.2 flashrom_dir := flashrom-$(flashrom_version) flashrom_tar := flashrom-$(flashrom_version).tar.bz2 flashrom_url := https://download.flashrom.org/releases/$(flashrom_tar) -flashrom_hash := 3702fa215ba5fb5af8e54c852d239899cfa1389194c1e51cb2a170c4dc9dee64 +flashrom_hash := e1f8d95881f5a4365dfe58776ce821dfcee0f138f75d0f44f8a3cd032d9ea42b flashrom_target := \ $(MAKE_JOBS) \ diff --git a/patches/flashrom-1.0/0100-enable-kgpe-d16.patch b/patches/flashrom-1.0/0100-enable-kgpe-d16.patch deleted file mode 100644 index 429e1867..00000000 --- a/patches/flashrom-1.0/0100-enable-kgpe-d16.patch +++ /dev/null @@ -1,2599 +0,0 @@ -diff --git ./Makefile ./Makefile -index 9cf52b2..3bc0d8c 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..cf28422 ---- /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 -+#include -+#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 -+#include -+#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 ./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 61a9af6..4adfd7d 100644 ---- ./cli_output.c -+++ ./cli_output.c -@@ -90,7 +90,8 @@ int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap - 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')) { - ret = vfprintf(logfile, fmt, logfile_args); - if (level != FLASHROM_MSG_SPEW) - fflush(logfile); -diff --git ./flash.h ./flash.h -index 9c3784b..58ad387 100644 ---- ./flash.h -+++ ./flash.h -@@ -119,6 +119,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, -@@ -164,6 +172,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; -@@ -347,6 +363,11 @@ __attribute__((format(printf, 2, 3))); - #define msg_pspew(...) print(FLASHROM_MSG_SPEW, __VA_ARGS__) /* programmer debug spew */ - #define msg_cspew(...) print(FLASHROM_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 read_romlayout(const char *name); -diff --git ./flashchips.c ./flashchips.c -index 7ef361b..c90fd94 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 15574bb..62eb9a5 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 c600efc..767c2c4 100644 ---- ./flashrom.c -+++ ./flashrom.c -@@ -6,6 +6,7 @@ - * Copyright (C) 2005-2008 coresystems GmbH - * Copyright (C) 2008,2009 Carl-Daniel Hailfinger - * Copyright (C) 2016 secunet Security Networks AG -+ * Copyright (C) 2016-2017 Raptor Engineering, LLC - * (Written by Nico Huber for secunet) - * - * This program is free software; you can redistribute it and/or modify -@@ -136,6 +137,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", -@@ -1600,6 +1625,18 @@ static int walk_eraseblocks(struct flashctx *const flashctx, - bool first = true; - struct block_eraser *const eraser = &flashctx->chip->block_erasers[erasefunction]; - -+ int show_progress = 0; -+ unsigned int percent_last, percent_current; -+ unsigned long size = flashctx->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 */ -+ } -+ - info->erase_start = 0; - for (i = 0; i < NUM_ERASEREGIONS; ++i) { - /* count==0 for all automatically initialized array -@@ -1620,6 +1657,14 @@ static int walk_eraseblocks(struct flashctx *const flashctx, - msg_cdbg(", "); - msg_cdbg("0x%06x-0x%06x:", info->erase_start, info->erase_end); - -+ if(show_progress) { -+ percent_current = (unsigned int) ((unsigned long long)info->erase_start * 100 / size); -+ if(percent_current != percent_last) { -+ msg_cinfo("\b\b\b%2d%%", percent_current); -+ percent_last = percent_current; -+ } -+ } -+ - ret = per_blockfn(flashctx, info, eraser->block_erase); - if (ret) - return ret; -@@ -1627,6 +1672,10 @@ static int walk_eraseblocks(struct flashctx *const flashctx, - if (info->region_end < info->erase_start) - break; - } -+ -+ if(show_progress) -+ msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */ -+ - msg_cdbg("\n"); - return 0; - } -@@ -2223,6 +2272,44 @@ int prepare_flash_access(struct flashctx *const flash, - 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"); -+ } -+ } -+ - return 0; - } - -diff --git ./pcidev.c ./pcidev.c -index f4e5542..d36e5c4 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 a98b713..c9c3a26 100644 ---- ./programmer.h -+++ ./programmer.h -@@ -5,6 +5,7 @@ - * Copyright (C) 2000 Ronald G. Minnich - * 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 -@@ -404,6 +411,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); -@@ -605,6 +624,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 ./spi.c ./spi.c -index c306ac3..817c8de 100644 ---- ./spi.c -+++ ./spi.c -@@ -112,7 +126,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. */ -diff --git ./spi25.c ./spi25.c -index 76242be..c324835 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) - { -@@ -967,7 +968,11 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, - lenhere = min(start + len, (i + 1) * area_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; - } -@@ -994,6 +999,16 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s - * we're OK for now. - */ - 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 -@@ -1012,7 +1027,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) -@@ -1020,8 +1038,20 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s - } - 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; - } - -@@ -1038,7 +1068,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 -+#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__ */ diff --git a/patches/flashrom-1.0/0101-enable-thinkpad-x220.patch b/patches/flashrom-1.0/0101-enable-thinkpad-x220.patch deleted file mode 100644 index 43f8b5ca..00000000 --- a/patches/flashrom-1.0/0101-enable-thinkpad-x220.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git ./board_enable.c ./board_enable.c -index b6e17ef..23acd7c 100644 ---- ./board_enable.c -+++ ./board_enable.c -@@ -2434,6 +2434,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 a/patches/flashrom-v1.2/0100-enable-kgpe-d16.patch b/patches/flashrom-v1.2/0100-enable-kgpe-d16.patch new file mode 100644 index 00000000..b4f8fa0b --- /dev/null +++ b/patches/flashrom-v1.2/0100-enable-kgpe-d16.patch @@ -0,0 +1,1097 @@ +diff --git a/Makefile b/Makefile +index 7242b09..c2fb32e 100644 +--- a/Makefile ++++ b/Makefile +@@ -236,6 +236,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 +@@ -492,6 +502,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 +@@ -616,6 +636,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 + +@@ -728,6 +754,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 +@@ -840,6 +868,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 a/ast1100.c b/ast1100.c +new file mode 100644 +index 0000000..c7474e5 +--- /dev/null ++++ b/ast1100.c +@@ -0,0 +1,420 @@ ++/* ++ * 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 ++#include ++#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 = { ++ .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 > 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) ++{ ++ unsigned 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 a/ast2400.c b/ast2400.c +new file mode 100644 +index 0000000..761a38d +--- /dev/null ++++ b/ast2400.c +@@ -0,0 +1,425 @@ ++/* ++ * 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 ++#include ++#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 = { ++ .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 > 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) ++{ ++ unsigned 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 a/flashchips.c b/flashchips.c +index 58dd4f3..719185b 100644 +--- a/flashchips.c ++++ b/flashchips.c +@@ -12273,7 +12273,7 @@ const struct flashchip flashchips[] = { + .total_size = 1024, + .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 = +@@ -16659,11 +16659,20 @@ const struct flashchip flashchips[] = { + .block_erasers = + { + { ++ .eraseblocks = { {4 * 1024, 8192} }, ++ .block_erase = spi_block_erase_21, ++ }, { + .eraseblocks = { {4 * 1024, 8192} }, + .block_erase = spi_block_erase_20, ++ }, { ++ .eraseblocks = { {32 * 1024, 1024} }, ++ .block_erase = spi_block_erase_5c, + }, { + .eraseblocks = { {32 * 1024, 1024} }, + .block_erase = spi_block_erase_52, ++ }, { ++ .eraseblocks = { {64 * 1024, 512} }, ++ .block_erase = spi_block_erase_dc, + }, { + .eraseblocks = { {64 * 1024, 512} }, + .block_erase = spi_block_erase_d8, +diff --git a/flashrom.c b/flashrom.c +index e540027..75bfd89 100644 +--- a/flashrom.c ++++ b/flashrom.c +@@ -6,6 +6,7 @@ + * Copyright (C) 2005-2008 coresystems GmbH + * Copyright (C) 2008,2009 Carl-Daniel Hailfinger + * Copyright (C) 2016 secunet Security Networks AG ++ * Copyright (C) 2016-2017 Raptor Engineering, LLC + * (Written by Nico Huber for secunet) + * + * This program is free software; you can redistribute it and/or modify +@@ -133,6 +134,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", +diff --git a/pcidev.c b/pcidev.c +index 54c1fd3..97c8c1f 100644 +--- a/pcidev.c ++++ b/pcidev.c +@@ -33,11 +33,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); +@@ -93,6 +95,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? */ +@@ -118,6 +126,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 a/programmer.h b/programmer.h +index 3cf53b9..7be47d1 100644 +--- a/programmer.h ++++ b/programmer.h +@@ -5,6 +5,7 @@ + * Copyright (C) 2000 Ronald G. Minnich + * 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 +@@ -43,6 +44,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 +@@ -401,6 +408,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);