ChrisEric1 CECL has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/72020 )
Change subject: Add AMD Ryzen Support & VIA VL805 Support ......................................................................
Add AMD Ryzen Support & VIA VL805 Support
Tested AMD Ryzen Support on HP Pavilion 590-p0077c, I am able to flash using F.15 or older, but can downgrade if newer FW is installed using afuwinx64 (vendor tool) This is due to flashrom SPI lockdown on newer firmwares by HP. It seems HP UEFI Diags uses AFU Flash embedded in. It also came with a AMD Ryzen 3 2200G. Also VL805 is working 100% for RPi4 USB XHCI FW Flashing, I had to change the RPi's chip (W25X10) to use rdid4 instead since it wouldn't work otherwise.
Change-Id: I7452b169ad89e0a884a46acc6a0499e97bb6ff7e Signed-off-by: Christopher Lentocha christopherericlentocha@gmail.com --- M Makefile M chipset_enable.c M flashchips.c M flashrom.8.tmpl M include/flashchips.h M include/programmer.h M programmer_table.c M sb600spi.c M spi25.c A vl805.c 10 files changed, 330 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/20/72020/1
diff --git a/Makefile b/Makefile index 425b58c..3148cf8 100644 --- a/Makefile +++ b/Makefile @@ -152,6 +152,7 @@ CONFIG_OGP_SPI \ CONFIG_SATAMV \ CONFIG_SATASII \ + CONFIG_VL805 \
DEPENDS_ON_LIBUSB1 := \ CONFIG_CH341A_SPI \ @@ -516,6 +517,9 @@ # Winchiphead CH341A CONFIG_CH341A_SPI ?= yes
+# Enable VIA VL805 programmer for now. +CONFIG_VL805 ?= yes + # Digilent Development board JTAG CONFIG_DIGILENT_SPI ?= yes
@@ -767,6 +771,11 @@ PROGRAMMER_OBJS += ch341a_spi.o endif
+ifeq ($(CONFIG_VL805), yes) +FEATURE_FLAGS += -D'CONFIG_VL805=1' +PROGRAMMER_OBJS += vl805.o +endif + ifeq ($(CONFIG_DIGILENT_SPI), yes) FEATURE_FLAGS += -D'CONFIG_DIGILENT_SPI=1' PROGRAMMER_OBJS += digilent_spi.o diff --git a/chipset_enable.c b/chipset_enable.c index b9144d1..af6bab2 100644 --- a/chipset_enable.c +++ b/chipset_enable.c @@ -1772,7 +1772,7 @@ {0x1022, 0x7440, B_PFL, OK, "AMD", "AMD-768", enable_flash_amd_768_8111}, {0x1022, 0x7468, B_PFL, OK, "AMD", "AMD-8111", enable_flash_amd_768_8111}, {0x1022, 0x780e, B_FLS, OK, "AMD", "FCH", enable_flash_sb600}, - {0x1022, 0x790e, B_FLS, OK, "AMD", "FP4", enable_flash_sb600}, + {0x1022, 0x790e, B_FLS, OK, "AMD", "FP4/FP5/AM4", enable_flash_sb600}, {0x1039, 0x0406, B_PFL, NT, "SiS", "501/5101/5501", enable_flash_sis501}, {0x1039, 0x0496, B_PFL, NT, "SiS", "85C496+497", enable_flash_sis85c496}, {0x1039, 0x0530, B_PFL, OK, "SiS", "530", enable_flash_sis530}, @@ -2179,6 +2179,7 @@ {0x8086, 0x7a8d, B_S, NT, "Intel", "WM690", enable_flash_pch600}, {0x8086, 0x7a8c, B_S, NT, "Intel", "HM670", enable_flash_pch600}, {0x8086, 0x7e23, B_S, DEP, "Intel", "Meteor Lake-P/M", enable_flash_mtl}, + {0x8086, 0xa3c8, B_S, OK, "Intel", "Comet Lake B460 LPC/eSPI", enable_flash_pch400}, #endif {0}, }; diff --git a/flashchips.c b/flashchips.c index 625fe62..caa82be 100644 --- a/flashchips.c +++ b/flashchips.c @@ -6384,6 +6384,45 @@
{ .vendor = "GigaDevice", + .name = "GD25LQ256", + .bustype = BUS_SPI, + .manufacture_id = GIGADEVICE_ID, + .model_id = GIGADEVICE_GD25LQ256, + .total_size = 32768, + .page_size = 256, + /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = + { + { + .eraseblocks = { {4 * 1024, 8192} }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {32 * 1024, 1024} }, + .block_erase = spi_block_erase_52, + }, { + .eraseblocks = { {64 * 1024, 512} }, + .block_erase = spi_block_erase_d8, + }, { + .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_bp4_srwd, + .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */ + .write = spi_chip_write_256, + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {1695, 2000}, + }, + + { + .vendor = "GigaDevice", .name = "GD25B128B/GD25Q128B", .bustype = BUS_SPI, .manufacture_id = GIGADEVICE_ID, @@ -17893,6 +17932,53 @@
{ .vendor = "Winbond", + .name = "W25Q256JW", + .bustype = BUS_SPI, + .manufacture_id = WINBOND_NEX_ID, + .model_id = WINBOND_NEX_W25Q256JW, + .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, + .tested = TEST_OK_PREW, + .probe = probe_spi_rdid4, + .probe_timing = TIMING_ZERO, + .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_52, + }, { + .eraseblocks = { {64 * 1024, 512} }, + .block_erase = spi_block_erase_dc, + }, { + .eraseblocks = { {64 * 1024, 512} }, + .block_erase = spi_block_erase_d8, + }, { + .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 = {1700, 1950}, + }, + + { + .vendor = "Winbond", .name = "W25Q256FV", .bustype = BUS_SPI, .manufacture_id = WINBOND_NEX_ID, diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl index 0eabee5..c1436fc 100644 --- a/flashrom.8.tmpl +++ b/flashrom.8.tmpl @@ -417,6 +417,8 @@ .sp .BR "* ch341a_spi" " (for SPI flash ROMs attached to WCH CH341A)" .sp +.BR "* vl805" " (for SPI flash ROMs attached to the VIA VL805 PCIe USB 3.0 Host controller)" +.sp .BR "* digilent_spi" " (for SPI flash ROMs attached to iCEblink40 development boards)" .sp .BR "* jlink_spi" " (for SPI flash ROMs attached to SEGGER J-Link and compatible devices)" @@ -1365,6 +1367,10 @@ .BR "ch341a_spi " programmer The WCH CH341A programmer does not support any parameters currently. SPI frequency is fixed at 2 MHz, and CS0 is used as per the device. +.BR "vl805 " programmer +This module supports SPI flash programming through the VL805/VL806 PCIe-USB 3.0 +Host controller. +.SS .SS .BR "ni845x_spi " programmer .IP @@ -1696,6 +1702,9 @@ .B ogp needs PCI configuration space read access and raw memory access. .sp +.B vl805 +needs PCI configuration space read access and raw memory access. +.sp .BR realtek_mst_i2c_spi " and " parade_lspcon need userspace access to the selected I2C bus. .sp diff --git a/include/flashchips.h b/include/flashchips.h index 5df42dc..c5f7f37 100644 --- a/include/flashchips.h +++ b/include/flashchips.h @@ -400,6 +400,7 @@ #define GIGADEVICE_GD25LQ32 0x6016 #define GIGADEVICE_GD25LQ64 0x6017 /* Same as GD25LQ64B (which is faster) */ #define GIGADEVICE_GD25LQ128CD 0x6018 +#define GIGADEVICE_GD25LQ256 0x6019 #define GIGADEVICE_GD25WQ80E 0x6514 #define GIGADEVICE_GD29GL064CAB 0x7E0601
@@ -977,6 +978,7 @@ #define WINBOND_NEX_W25Q32_W 0x6016 /* W25Q32DW; W25Q32FV in QPI mode */ #define WINBOND_NEX_W25Q64_W 0x6017 /* W25Q64DW; W25Q64FV in QPI mode */ #define WINBOND_NEX_W25Q128_W 0x6018 /* W25Q128FW; W25Q128FV in QPI mode */ +#define WINBOND_NEX_W25Q256JW 0x6019 /* W25Q256JW */ #define WINBOND_NEX_W25Q256_W 0x6019 /* W25Q256JW */ #define WINBOND_NEX_W25Q64JV 0x7017 /* W25Q64JV */ #define WINBOND_NEX_W25Q128_V_M 0x7018 /* W25Q128JVSM */ diff --git a/include/programmer.h b/include/programmer.h index 9e706d5..eae7899 100644 --- a/include/programmer.h +++ b/include/programmer.h @@ -25,6 +25,8 @@
#include "flash.h" /* for chipaddr and flashctx */
+extern uint8_t RZN32BM; + enum programmer_type { PCI = 1, /* to detect uninitialized values */ USB, @@ -60,6 +62,7 @@ extern const struct programmer_entry programmer_atavia; extern const struct programmer_entry programmer_buspirate_spi; extern const struct programmer_entry programmer_ch341a_spi; +extern const struct programmer_entry programmer_vl805; extern const struct programmer_entry programmer_dediprog; extern const struct programmer_entry programmer_developerbox; extern const struct programmer_entry programmer_digilent_spi; diff --git a/programmer_table.c b/programmer_table.c index d58a155..4fb705a 100644 --- a/programmer_table.c +++ b/programmer_table.c @@ -152,6 +152,10 @@ &programmer_ch341a_spi, #endif
+#if CONFIG_VL805 == 1 + &programmer_vl805, +#endif + #if CONFIG_DIGILENT_SPI == 1 &programmer_digilent_spi, #endif diff --git a/sb600spi.c b/sb600spi.c index 5b9ac45..4c287b7 100644 --- a/sb600spi.c +++ b/sb600spi.c @@ -53,6 +53,7 @@
#define FIFO_SIZE_OLD 8 #define FIFO_SIZE_YANGTZE 71 +uint8_t RZN32BM = 0;
#define SPI100_CMD_CODE_REG 0x45 #define SPI100_CMD_TRIGGER_REG 0x47 @@ -124,6 +125,11 @@ if (rev == 0x4a) { msg_pdbg("Yangtze detected.\n"); return CHIPSET_YANGTZE; + } else if (rev == 0x51 || rev == 0x59 || rev == 0x61) { + //RZN32BM = mmio_readb(sb600_spibar + 0x50) & 0x1; + //amd_gen = CHIPSET_YANGTZE; + msg_pdbg("Ryzen detected.\n"); + return CHIPSET_YANGTZE; /** * FCH chipsets called 'Promontory' are one's with the * so-called SPI100 ip core that uses memory mapping and @@ -513,7 +519,14 @@ tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3; msg_pdbg("NormSpeed is %s\n", spispeeds[tmp]); if (spispeed_idx < 0) { - spispeed_idx = 3; /* Default to 16.5 MHz */ + if (amd_gen >= CHIPSET_YANGTZE) + { + spispeed_idx = 1; /* Default to 33.3 MHz */ + } + else + { + spispeed_idx = 3; /* Default to 16.5 MHz */ + } } } if (spispeed_idx < 0) { diff --git a/spi25.c b/spi25.c index f54e4c8..25b5bcb 100644 --- a/spi25.c +++ b/spi25.c @@ -393,7 +393,10 @@ const bool native_4ba, const unsigned int addr) { if (native_4ba || flash->in_4ba_mode) { - if (!spi_master_4ba(flash)) { + if (!spi_master_4ba(flash) && RZN32BM != 1) { + msg_cwarn("4-byte address requested but master can't handle 4-byte addresses.\n"); + return -1; + } else if (!spi_master_4ba(flash)) { msg_cwarn("4-byte address requested but master can't handle 4-byte addresses.\n"); return -1; } diff --git a/vl805.c b/vl805.c new file mode 100644 index 0000000..be1093a --- /dev/null +++ b/vl805.c @@ -0,0 +1,183 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2019, 2020 Carl-Daniel Hailfinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Driver for the VIA VL805 programmer hardware by VIA. + * See http://www.via.com/ for more info. + */ + +#include "programmer.h" +#include "spi.h" +#include "flash.h" +//#include "hwaccess.h" +#include "hwaccess_x86_io.h" +#include "platform/pci.h" + +extern const struct dev_entry devs_vl805[]; + +const struct dev_entry devs_vl805[] = { + {0x1106, 0x3483, OK, "VIA", "VL805"}, + {0}, +}; + +static struct pci_dev *dev = NULL; + +static void vl805_setregval(int reg, uint32_t val) +{ + pci_write_long(dev, 0x78, reg); + pci_write_long(dev, 0x7c, val); +} + +static uint32_t vl805_getregval(int reg) +{ + pci_write_long(dev, 0x78, reg); + + return pci_read_long(dev, 0x7c); +} + +/* Some of the registers have unknown purpose and are just used inside the init sequence replay. */ +#define VL805_REG_0x30004 0x00030004 +#define VL805_REG_STOP_POLLING 0x0004000c +#define VL805_REG_WB_EN 0x00040020 +#define VL805_REG_SPI_OUTDATA 0x000400d0 +#define VL805_REG_SPI_INDATA 0x000400e0 +#define VL805_REG_SPI_TRANSACTION 0x000400f0 +#define VL805_REG_CLK_DIV 0x000400f8 +#define VL805_REG_SPI_CHIP_ENABLE_LEVEL 0x000400fc + +/* Send a SPI command to the flash chip. */ +static int vl805_spi_send_command(const struct flashctx *flash, + unsigned int writecnt, + unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr) +{ + unsigned int i, j; + uint32_t outdata; + uint32_t indata = 0; + unsigned int curwritecnt = 0; + unsigned int curreadcnt = 0; + + vl805_setregval(VL805_REG_SPI_CHIP_ENABLE_LEVEL, 0x00000000); + + for (j = 0; j < writecnt; j += 4) { + curwritecnt = min(4, writecnt - j); + outdata = 0; + for (i = 0; i < curwritecnt; i++) { + outdata <<= 8; + outdata |= writearr[j + i]; + } + vl805_setregval(VL805_REG_SPI_OUTDATA, outdata); + vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x00000580 | (curwritecnt << 3)); + } + + /* Superfluous, the original driver doesn't do that, but we want to have a quiet bus during read. */ + vl805_setregval(VL805_REG_SPI_OUTDATA, 0); + + for (j = 0; j < readcnt; j += 4) { + curreadcnt = min(4, readcnt - j); + vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x00000580 | (curreadcnt << 3)); + indata = vl805_getregval(VL805_REG_SPI_INDATA); + for (i = 0; i < curreadcnt; i++) { + unsigned pos = curreadcnt - (i + 1); + readarr[j + i] = (indata >> (8 * pos)) & 0xff; + } + } + + vl805_setregval(VL805_REG_SPI_CHIP_ENABLE_LEVEL, 0x00000001); + + return 0; +} + +static const struct spi_master spi_master_vl805 = { + .max_data_read = 64 * 1024, /* Maximum data read size in one go (excluding opcode+address). */ + .max_data_write = 256, /* Maximum data write size in one go (excluding opcode+address). */ + .command = vl805_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, + .write_aai = default_spi_write_aai, + .probe_opcode = default_spi_probe_opcode, +}; + +static void vl805_programmer_active(uint8_t val) +{ + pci_write_byte(dev, 0x43, val); +} + +static int vl805_shutdown(void *data) +{ + /* Shutdown stuff. */ + vl805_programmer_active(0x0); + + return 0; +} + +int vl805_init(void); + +int vl805_init(void) +{ + uint32_t val; + + #if defined(__i386__) || defined(__x86_64__) + if (rget_io_perms()) + return 1; + #endif + + dev = pcidev_init(devs_vl805, PCI_BASE_ADDRESS_0); /* Actually no BAR setup needed at all. */ + if (!dev) + return 1; + + vl805_programmer_active(0x1); + val = pci_read_long(dev, 0x50); + msg_pdbg("VL805 firmware version 0x%08x\n", val); + vl805_programmer_active(0x0); + + /* Some sort of init sequence, just copied from the logs. */ + vl805_programmer_active(0x1); + + vl805_setregval(VL805_REG_SPI_CHIP_ENABLE_LEVEL, 0x00000001); + vl805_setregval(VL805_REG_0x30004, 0x00000200); + vl805_setregval(VL805_REG_WB_EN, 0xffffff01); + vl805_setregval(VL805_REG_STOP_POLLING, 0x00000001); + + /* We send 4 uninitialized(?) bytes to the flash chip here. */ + vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x000005a0); + vl805_setregval(VL805_REG_CLK_DIV, 0x0000000a); + + /* Some sort of cleanup sequence, just copied from the logs. */ + vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x00000000); + vl805_programmer_active(0x0); + + register_shutdown(vl805_shutdown, NULL); + vl805_programmer_active(0x1); + + register_spi_master(&spi_master_vl805, NULL); + + return 0; +} + +const struct programmer_entry programmer_vl805 = { + .name = "vl805", + .type = PCI, + .devs.dev = devs_vl805, + .init = vl805_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, +};