Skip to content

Instantly share code, notes, and snippets.

@cleverca22
Created January 19, 2020 21:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cleverca22/426715da598b338e97de5d896db92e30 to your computer and use it in GitHub Desktop.
Save cleverca22/426715da598b338e97de5d896db92e30 to your computer and use it in GitHub Desktop.
diff --git a/Makefile b/Makefile
index 7242b09..cb711ba 100644
--- a/Makefile
+++ b/Makefile
@@ -696,6 +696,11 @@ CONFIG_DIGILENT_SPI ?= yes
# Disable J-Link for now.
CONFIG_JLINK_SPI ?= no
+# Enable VIA VL805 programmer for now.
+CONFIG_VL805 ?= yes
+
+#PLACEHOLDER_NEWPROG_DEFAULTCONFIG
+
# Disable wiki printing by default. It is only useful if you have wiki access.
CONFIG_PRINT_WIKI ?= no
@@ -759,7 +764,9 @@ else
ifeq ($(CONFIG_OGP_SPI), yes)
override CONFIG_BITBANG_SPI = yes
else
+#PLACEHOLDER_NEWPROG_BITBANGSPICONFIG1
CONFIG_BITBANG_SPI ?= no
+#PLACEHOLDER_NEWPROG_BITBANGSPICONFIG2
endif
endif
endif
@@ -996,6 +1003,14 @@ NEED_LINUX_I2C += CONFIG_MSTARDDC_SPI
PROGRAMMER_OBJS += mstarddc_spi.o
endif
+ifeq ($(CONFIG_VL805), yes)
+FEATURE_CFLAGS += -D'CONFIG_VL805=1'
+PROGRAMMER_OBJS += vl805.o
+NEED_PCI := yes
+endif
+
+#PLACEHOLDER_NEWPROG_COMPILERULE
+
ifeq ($(CONFIG_CH341A_SPI), yes)
FEATURE_CFLAGS += -D'CONFIG_CH341A_SPI=1'
PROGRAMMER_OBJS += ch341a_spi.o
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index aa5bcd4..6997dd9 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -345,6 +345,9 @@ bitbanging adapter)
.sp
.BR "* stlinkv3_spi" " (for SPI flash ROMs attached to STMicroelectronics STLINK V3 devices)"
.sp
+.BR "* vl805" " (VIA VL805 programmer)"
+.sp
+.\"PLACEHOLDER_NEWPROG_MAN_SHORTDESCRIPTION
Some programmers have optional or mandatory parameters which are described
in detail in the
.B PROGRAMMER-SPECIFIC INFORMATION
@@ -1287,7 +1290,10 @@ syntax where \fBfrequency\fP is the SPI clock frequency in kHz.
If the passed frequency is not supported by the adapter the nearest lower
supported frequency will be used.
.SS
-
+.BR "vl805 " programmer
+Please describe the programmer parameters here.
+.SS
+.\"PLACEHOLDER_NEWPROG_MAN_LONGDESCRIPTION
.SH EXAMPLES
To back up and update your BIOS, run
.sp
@@ -1365,6 +1371,10 @@ permissions are set.
.B ogp
needs PCI configuration space read access and raw memory access.
.sp
+.B vl805
+Please describe the programmer requirements here.
+.sp
+.\"PLACEHOLDER_NEWPROG_MAN_REQUIREMENTS
On OpenBSD, you can obtain raw access permission by setting
.B "securelevel=-1"
in
diff --git a/flashrom.c b/flashrom.c
index e540027..dc2224a 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -473,6 +473,19 @@ const struct programmer_entry programmer_table[] = {
},
#endif
+#if CONFIG_VL805 == 1
+ {
+ .name = "vl805",
+ .type = PCI,
+ .devs.dev = devs_vl805,
+ .init = vl805_init,
+ .map_flash_region = fallback_map,
+ .unmap_flash_region = fallback_unmap,
+ .delay = internal_delay,
+ },
+#endif
+
+//PLACEHOLDER_NEWPROG_PROGRAMMER_ARRAY
{0}, /* This entry corresponds to PROGRAMMER_INVALID. */
};
diff --git a/pcidev.c b/pcidev.c
index 4012840..2afa749 100644
--- a/pcidev.c
+++ b/pcidev.c
@@ -237,6 +237,7 @@ struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar)
*/
if ((addr = pcidev_validate(dev, bar, devs)) != 0) {
found++;
+ break;
}
}
}
diff --git a/programmer.h b/programmer.h
index 3cf53b9..3a0baa7 100644
--- a/programmer.h
+++ b/programmer.h
@@ -127,6 +127,10 @@ enum programmer {
#if CONFIG_STLINKV3_SPI == 1
PROGRAMMER_STLINKV3_SPI,
#endif
+#if CONFIG_VL805 == 1
+ PROGRAMMER_VL805,
+#endif
+//PLACEHOLDER_NEWPROG_PROGRAMMER_ENUM
PROGRAMMER_INVALID /* This must always be the last entry. */
};
@@ -573,6 +577,15 @@ int jlink_spi_init(void);
int ni845x_spi_init(void);
#endif
+/* vl805.c */
+#if CONFIG_VL805 == 1
+int vl805_init(void);
+extern const struct dev_entry devs_vl805[];
+
+#endif
+
+//PLACEHOLDER_NEWPROG_PUBLICFUNCTIONS
+
/* flashrom.c */
struct decode_sizes {
uint32_t parallel;
diff --git a/vl805.c b/vl805.c
new file mode 100644
index 0000000..e407a6b
--- /dev/null
+++ b/vl805.c
@@ -0,0 +1,181 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2019 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 "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+#include "spi.h"
+
+const struct dev_entry devs_vl805[] = {
+ {0x1106, 0x3483, NT, "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_0x4000c 0x0004000c // STOP_POLLING
+#define VL805_REG_0x40020 0x00040020 // PCI_WB_EN
+#define VL805_REG_SPI_OUTDATA 0x000400d0
+#define VL805_REG_SPI_INDATA 0x000400e0
+#define VL805_REG_SPI_TRANSACTION 0x000400f0
+#define VL805_REG_0x400f8 0x000400f8
+#define VL805_REG_SPI_CHIP_ENABLE_LEVEL 0x000400fc
+
+static int vl805_spi_send_command(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;
+
+ if (writecnt > 4) {
+ return 1;
+ }
+ if (readcnt > 4) {
+ return 1;
+ }
+ /* Send a SPI command to the flash chip. */
+
+ vl805_setregval(VL805_REG_SPI_CHIP_ENABLE_LEVEL, 0x00000000);
+
+ /* FIXME: Test this for writecnt > 4. */
+ 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. */
+ vl805_setregval(VL805_REG_SPI_OUTDATA, 0);
+
+ /* FIXME: Test this for readcnt > 4. */
+ 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);
+ indata <<= (4 - curreadcnt) * 8;
+ for (i = 0; i < curreadcnt; i++) {
+ readarr[j + i] = (indata & 0xff000000) >> 24;
+ indata <<= 8;
+ }
+ }
+
+ 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,
+};
+
+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)
+{
+ if (rget_io_perms())
+ return 1;
+
+ dev = pcidev_init(devs_vl805, PCI_BASE_ADDRESS_0); /* Actually no BAR setup needed at all. */
+ msg_pdbg("pcidev_init returned %p\n", dev);
+ if (!dev)
+ return 1;
+
+ vl805_programmer_active(0x1);
+ uint32_t 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);
+
+ val = vl805_getregval(VL805_REG_0x30004);
+ val &= ~0xff00;
+ val |= 0x200;
+ vl805_setregval(VL805_REG_0x30004, val);
+
+ val = vl805_getregval(VL805_REG_0x40020);
+ val &= ~0x00ff;
+ val |= 0x001;
+ vl805_setregval(VL805_REG_0x40020, 0xffffff01);
+
+ val = vl805_getregval(VL805_REG_0x4000c);
+ val &= ~0xff;
+ val |= 0x1;
+ vl805_setregval(VL805_REG_0x4000c, 0x00000001);
+
+ /* We send 4 uninitialized(?) bytes to the flash chip here. */
+ vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x000005a0);
+ vl805_setregval(VL805_REG_0x400f8, 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);
+
+ return 0;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment