ChrisEric1 CECL has uploaded this change for review.

View Change

Add support for VIA VL805 USB 3 XHCI flashing

It works fine for me on my Raspberry Pi 4 Model B.

Was able read read, erase, write, verify.

Only thing is the WP with the W25X10 gives a untested warning.

And I changed W25X10 to RDID4 since it wouldn't work otherwise.

Change-Id: I71435afcacdf97e14d627e35bce3d29de9657f38
Signed-off-by: Christopher Lentocha <christopherericlentocha@gmail.com>
---
M Makefile
M flashchips.c
M flashrom.8.tmpl
M include/programmer.h
M programmer_table.c
A vl805.c
6 files changed, 262 insertions(+), 1 deletion(-)

git pull ssh://review.coreboot.org:29418/flashrom refs/changes/57/72057/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/flashchips.c b/flashchips.c
index 625fe62..db72ee4 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -7783,6 +7783,46 @@

{
.vendor = "ISSI",
+ .name = "IS25LP080D",
+ .bustype = BUS_SPI,
+ .manufacture_id = 0x9D,
+ .model_id = 0x6014,
+ .total_size = 1024,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID4,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "ISSI",
.name = "IS29GL064B",
.bustype = BUS_PARALLEL,
.manufacture_id = ISSI_ID,
@@ -19123,7 +19163,7 @@
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = PROBE_SPI_RDID,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
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/programmer.h b/include/programmer.h
index 9e706d5..30c1dc2 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -60,6 +60,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/vl805.c b/vl805.c
new file mode 100644
index 0000000..8374063
--- /dev/null
+++ b/vl805.c
@@ -0,0 +1,180 @@
+/*
+ * 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(const struct programmer_cfg *cfg);
+
+int vl805_init(const struct programmer_cfg *cfg)
+{
+ uint32_t val;
+
+ #if defined(__i386__) || defined(__x86_64__)
+ if (rget_io_perms())
+ return 1;
+ #endif
+
+ dev = pcidev_init(cfg, 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,
+};

To view, visit change 72057. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I71435afcacdf97e14d627e35bce3d29de9657f38
Gerrit-Change-Number: 72057
Gerrit-PatchSet: 1
Gerrit-Owner: ChrisEric1 CECL <christopherericlentocha@gmail.com>
Gerrit-MessageType: newchange