VIA VL805 support, first draft. No idea if it actually works.
It is highly likely that SPI accesses with a readcnt not being a
multiple of 4 will return incorrect data due to the unknown encoding of
the register containing SPI responses of the chip. That will be obvious
from any verbose log, though, and once I have such data, adjusting the
code is trivial.

Reverse engineered based on PCI traces created by cleverca22 on a
Raspberry Pi 4 Model B.

RFC, with some unrelated (automatic programmer driver writer) and some
related changes (buggy PCI patch reverted).

In case someone is feeling less brave, I also have a version which
aborts early after the init sequence.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2...@gmx.net>

diff -r 7bf17529e516 Makefile
--- a/Makefile  Tue Dec 31 18:22:02 2019 +0100
+++ b/Makefile  Wed Jan 15 13:20:27 2020 +0100
@@ -696,6 +696,11 @@
 # 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 @@
 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 @@
 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 -r 7bf17529e516 atavia.c
--- a/atavia.c  Tue Dec 31 18:22:02 2019 +0100
+++ b/atavia.c  Wed Jan 15 13:20:27 2020 +0100
@@ -142,7 +142,7 @@
        if (rget_io_perms())
                return 1;

-       dev = pcidev_init(ata_via, PCI_ROM_ADDRESS); /* Acutally no BAR setup 
needed at all. */
+       dev = pcidev_init(ata_via, PCI_ROM_ADDRESS); /* Actually no BAR setup 
needed at all. */
        if (!dev)
                return 1;

diff -r 7bf17529e516 build_new_driver.sh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/build_new_driver.sh       Wed Jan 15 13:20:27 2020 +0100
@@ -0,0 +1,419 @@
+#!/bin/bash
+# flashrom programmer driver skeleton builder.
+# Copyright 2012,2020 Carl-Daniel Hailfinger
+# Licensed under the GNU GPL v2
+# The license of the generated programmer driver is unrelated to the licsense
+# of this script and can be specified below.
+
+# Fill in all info in the block below, and don't touch anything else.
+# The data provided here is just an example.
+# Name of the programmer. Needs to be an all-lowercase valid C identifier.
+PROGRAMMERNAME=vl805
+# Short description of the programmer. Please do not use / inside the name, it 
will break the sed expressions.
+PROGRAMMERDESCR="VIA VL805 programmer"
+# Name of the programmer manufacturer.
+PROGRAMMERMANUF="VIA"
+# Website for the programmer.
+PROGRAMMERURL="http://www.via.com/";
+# Fill in your name here.
+AUTHORNAME="Carl-Daniel Hailfinger"
+# License version of the new programmer driver: 2 or 2+ (for 2+later)
+LICENSE_GPL=2
+# Does the programmer need a map/unmap function?
+HAVE_MAP=no
+# Does the programmer have its own delay function?
+HAVE_DELAY=no
+# Does the programmer need some sort of direct hardware access?
+NEED_PCI=yes
+# Does the programmer need some sort of serial port access?
+NEED_SERIAL=no
+# Is the programmer a PCI device, USB device, or something else?
+# You have to specify exactly one of PCI, USB, OTHER
+DEVICETYPE=PCI
+# Note: Usually a programmer only has one of NEED_PARLPCFWH, NEED_SPI or 
NEED_SPI_BITBANG set to yes.
+# Does the programmer use Parallel/LPC/FWH functionality?
+NEED_PARLPCFWH=no
+# Which of PARALLEL/LPC/FWH buses does the programer use? FIXME: Explain how 
to handle multiple buses.
+BUS_PARLPCFWH=none
+# Does the programmer use SPI functionality without bitbanging? FIXME: Check 
if a SPI bitbanging driver with NEED_SPI=no generates useful code.
+NEED_SPI=yes
+# Does the programmer use the bitbanging SPI infrastructure?
+NEED_SPI_BITBANG=no
+
+# No user serviceable parts below.
+unset LANG
+unset LANGUAGE
+unset LC_COLLATE
+if test $LICENSE_GPL = 2; then
+       GPLV3EITHER=
+       GPLV3OR=
+elif test $LICENSE_GPL = 2+; then
+       GPLV3EITHER="either"
+       GPLV3OR="\n * (at your option) any later version"
+else
+       echo "Specified license can not be handled automatically"
+       exit 1
+fi
+if test $HAVE_MAP = yes; then MAPNAME=$PROGRAMMERNAME; else MAPNAME=fallback; 
fi
+if test $HAVE_DELAY = yes; then DELAYNAME=$PROGRAMMERNAME; else 
DELAYNAME=internal; fi
+PROGRAMMERNAMECAPS=$(echo -n $PROGRAMMERNAME|tr "[[:lower:]]" "[[:upper:]]")
+CONFIGNAME=CONFIG_$PROGRAMMERNAMECAPS
+ENUMNAME=PROGRAMMER_$PROGRAMMERNAMECAPS
+if test $NEED_PCI = yes; then NEEDS="NEED_PCI := yes\n"; fi
+if test $NEED_SERIAL = yes; then NEEDS+="NEED_SERIAL := yes\n"; fi
+
+sed "s-^//PLACEHOLDER_NEWPROG_PROGRAMMER_ARRAY-\
+#if ${CONFIGNAME} == 1\n\
+       {\n\
+               .name                   = \"${PROGRAMMERNAME}\",\n\
+\0-" flashrom.c >flashrom.c.mine
+if test $DEVICETYPE = OTHER; then
+sed "s-^//PLACEHOLDER_NEWPROG_PROGRAMMER_ARRAY-\
+               .type                   = OTHER,\n\
+               .devs.note              = \"Textual list of usable 
devices\\\\n\",\n\
+\0-" flashrom.c.mine >flashrom.c.mine1
+mv flashrom.c.mine1 flashrom.c.mine
+else
+sed "s-^//PLACEHOLDER_NEWPROG_PROGRAMMER_ARRAY-\
+               .type                   = ${DEVICETYPE},\n\
+               .devs.dev               = devs_${PROGRAMMERNAME},\n\
+\0-" flashrom.c.mine >flashrom.c.mine1
+mv flashrom.c.mine1 flashrom.c.mine
+fi
+sed "s-^//PLACEHOLDER_NEWPROG_PROGRAMMER_ARRAY-\
+               .init                   = ${PROGRAMMERNAME}_init,\n\
+               .map_flash_region       = ${MAPNAME}_map,\n\
+               .unmap_flash_region     = ${MAPNAME}_unmap,\n\
+               .delay                  = ${DELAYNAME}_delay,\n\
+       },\n\
+#endif\n\
+\n\0-" flashrom.c.mine >flashrom.c.mine1
+mv flashrom.c.mine1 flashrom.c.mine
+
+sed -e "s/^#PLACEHOLDER_NEWPROG_DEFAULTCONFIG/\
+# Enable ${PROGRAMMERDESCR} for now.\n\
+${CONFIGNAME} ?= yes\n\
+\n\0/" \
+-e "s/^#PLACEHOLDER_NEWPROG_COMPILERULE/\
+ifeq (\$(${CONFIGNAME}), yes)\n\
+FEATURE_CFLAGS += -D'${CONFIGNAME}=1'\n\
+PROGRAMMER_OBJS += ${PROGRAMMERNAME}.o\n\
+${NEEDS}\
+endif\n\
+\n\0/" Makefile >Makefile.mine
+
+if test $NEED_SPI_BITBANG = yes; then
+sed -e "s/^#PLACEHOLDER_NEWPROG_BITBANGSPICONFIG1/\
+ifeq (\$(${CONFIGNAME}), yes)\n\
+override CONFIG_BITBANG_SPI = yes\n\
+else\n\
+\0/" \
+-e "s/^#PLACEHOLDER_NEWPROG_BITBANGSPICONFIG2/\
+\0\n\
+endif/;" Makefile.mine >Makefile.mine1
+mv Makefile.mine1 Makefile.mine
+fi
+
+sed -e "s-^//PLACEHOLDER_NEWPROG_PROGRAMMER_ENUM-\
+#if ${CONFIGNAME} == 1\n\
+       ${ENUMNAME},\n\
+#endif\n\
+\0-" \
+-e "s-^//PLACEHOLDER_NEWPROG_PUBLICFUNCTIONS-\
+/* ${PROGRAMMERNAME}.c */\n\
+#if ${CONFIGNAME} == 1\n\
+int ${PROGRAMMERNAME}_init(void);\n\
+\0-" programmer.h >programmer.h.mine
+
+if test $DEVICETYPE = PCI -o $DEVICETYPE = USB; then
+sed -e "s-^//PLACEHOLDER_NEWPROG_PUBLICFUNCTIONS-\
+extern const struct dev_entry devs_${PROGRAMMERNAME}[];\n\
+\n\0-" programmer.h.mine >programmer.h.mine1
+mv programmer.h.mine1 programmer.h.mine
+fi
+
+sed -e "s-^//PLACEHOLDER_NEWPROG_PUBLICFUNCTIONS-\
+#endif\n\
+\n\0-" programmer.h.mine >programmer.h.mine1
+mv programmer.h.mine1 programmer.h.mine
+
+if test $NEED_SPI_BITBANG = yes; then
+sed -e "s-//PLACEHOLDER_NEWPROG_SELECT_SPI_BITBANG\$-\
+|| ${CONFIGNAME} == 1 \0-" programmer.h.mine >programmer.h.mine1
+mv programmer.h.mine1 programmer.h.mine
+fi
+
+# No idea if roff supports hidden comments. Hook up to hopefully unchanged 
sequences.
+sed -e "s/.*PLACEHOLDER_NEWPROG_MAN_SHORTDESCRIPTION/\
+.BR \"* ${PROGRAMMERNAME}\" \" (${PROGRAMMERDESCR})\"\n\
+.sp\n\
+\0/" \
+-e "s/.*PLACEHOLDER_NEWPROG_MAN_LONGDESCRIPTION/\
+.SS\n\
+.BR \"${PROGRAMMERNAME} \" programmer\n\
+Please describe the programmer parameters here.\n\
+\0/" \
+-e "s/.*PLACEHOLDER_NEWPROG_MAN_REQUIREMENTS/\
+.B ${PROGRAMMERNAME}\n\
+Please describe the programmer requirements here.\n\
+.sp\n\
+\0/" flashrom.8.tmpl > flashrom.8.tmpl.mine
+
+cat >$PROGRAMMERNAME.c.mine <<EOF
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) $(date +%Y) ${AUTHORNAME}
+ *
+ * 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; ${GPLV3EITHER}version 2 of the 
License${GPLV3OR}.
+ *
+ * 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 ${PROGRAMMERDESCR} hardware by ${PROGRAMMERMANUF}.
+ * See ${PROGRAMMERURL} for more info.
+ */
+
+#include "flash.h"
+#include "programmer.h"
+
+EOF
+
+if test $DEVICETYPE = PCI -o $DEVICETYPE = USB; then
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+const struct dev_entry devs_${PROGRAMMERNAME}[] = {
+       {0xdead, 0xbeef, NT, "Vendor name", "Device name"},
+
+       {0},
+};
+
+EOF
+fi
+
+if test $NEED_PARLPCFWH = yes; then
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+static void ${PROGRAMMERNAME}_chip_writeb(const struct flashctx *flash, 
uint8_t val, chipaddr addr)
+{
+       /* Write a byte to the flash chip. */
+}
+
+static uint8_t ${PROGRAMMERNAME}_chip_readb(const struct flashctx *flash, 
const chipaddr addr)
+{
+       /* Read a byte from the flash chip and return it. */
+       /* Set it to 0xff to get the template to compile. */
+       uint8_t val = 0xff;
+
+       return val;
+}
+
+static const struct par_programmer par_programmer_${PROGRAMMERNAME} = {
+               .chip_readb             = ${PROGRAMMERNAME}_chip_readb,
+               /* If your programmer supports word/long accesses, change the 
lines below. */
+               .chip_readw             = fallback_chip_readw,
+               .chip_readl             = fallback_chip_readl,
+               .chip_readn             = fallback_chip_readn,
+               .chip_writeb            = ${PROGRAMMERNAME}_chip_writeb,
+               .chip_writew            = fallback_chip_writew,
+               .chip_writel            = fallback_chip_writel,
+               .chip_writen            = fallback_chip_writen,
+};
+
+EOF
+fi
+
+if test $NEED_SPI_BITBANG = yes; then
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+static void ${PROGRAMMERNAME}_bitbang_set_cs(int val)
+{
+       /* Set/clear the CS# line. */
+}
+
+static void ${PROGRAMMERNAME}_bitbang_set_sck(int val)
+{
+       /* Set/clear the SCLK line. */
+}
+
+static void ${PROGRAMMERNAME}_bitbang_set_mosi(int val)
+{
+       /* Set/clear the MOSI line. */
+}
+
+static int ${PROGRAMMERNAME}_bitbang_get_miso(void)
+{
+       /* Get the state of the MISO line and return it. */
+       /* Set it to 1 to get the template to compile. */
+       int misoval = 1;
+
+       return misoval;
+}
+
+/* If this programmer does not support requesting/releasing the SPI bus, remove
+ * the functions ${PROGRAMMERNAME}_request_spibus and 
${PROGRAMMERNAME}_release_spibus
+ * and set bitbang_spi_master_${PROGRAMMERNAME} members .request_bus and 
.release_bus
+ * to NULL.
+ */
+static void ${PROGRAMMERNAME}_request_spibus(void)
+{
+}
+
+static void ${PROGRAMMERNAME}_release_spibus(void)
+{
+}
+
+static const struct bitbang_spi_master bitbang_spi_master_${PROGRAMMERNAME} = {
+       .set_cs = ${PROGRAMMERNAME}_bitbang_set_cs,
+       .set_sck = ${PROGRAMMERNAME}_bitbang_set_sck,
+       .set_mosi = ${PROGRAMMERNAME}_bitbang_set_mosi,
+       .get_miso = ${PROGRAMMERNAME}_bitbang_get_miso,
+       .request_bus = ${PROGRAMMERNAME}_request_spibus,
+       .release_bus = ${PROGRAMMERNAME}_release_spibus,
+       .half_period = 1, /* Delay in microseconds before each SCLK level 
change. */
+};
+
+EOF
+fi
+
+if test $NEED_SPI = yes; then
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+/* Include string.h for memset to get the template to compile. Remove this. */
+#include <string.h>
+static int ${PROGRAMMERNAME}_spi_send_command(struct flashctx *flash,
+                       unsigned int writecnt, unsigned int readcnt,
+                       const unsigned char *writearr,
+                       unsigned char *readarr)
+{
+       /* Send a SPI command to the flash chip. */
+       /* Set readarr to 0xff to get the template to compile and run without 
segfaults. */
+       memset(readarr, 0xff, readcnt);
+
+       return 0;
+}
+
+static const struct spi_master spi_master_${PROGRAMMERNAME} = {
+       .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        = ${PROGRAMMERNAME}_spi_send_command,
+       .multicommand   = default_spi_send_multicommand,
+       .read           = default_spi_read,
+       .write_256      = default_spi_write_256,
+};
+
+EOF
+fi
+
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+static int ${PROGRAMMERNAME}_shutdown(void *data)
+{
+       /* Shutdown stuff. */
+       return 0;
+}
+
+int ${PROGRAMMERNAME}_init(void)
+{
+       /* Init stuff (i.e. parameter parsing) here which does not need to be
+        * undone.
+        */
+
+       /* If your shutdown function takes a parameter, replace NULL with it. */
+       register_shutdown(${PROGRAMMERNAME}_shutdown, NULL);
+
+       /* Init stuff which needs to be undone on shutdown. */
+
+EOF
+
+if test $NEED_SPI_BITBANG = yes; then
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+       /* 1 usec halfperiod delay, change as needed. */
+       if (bitbang_spi_init(&bitbang_spi_master_${PROGRAMMERNAME}))
+               return 1;
+
+EOF
+fi
+
+if test $NEED_SPI = yes; then
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+       register_spi_master(&spi_master_${PROGRAMMERNAME});
+
+EOF
+fi
+
+if test $NEED_PARLPCFWH = yes; then
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+       register_par_programmer(&par_programmer_${PROGRAMMERNAME}, 
BUS_${BUS_PARLPCFWH});
+
+EOF
+fi
+
+cat >>$PROGRAMMERNAME.c.mine <<EOF
+       return 0;
+}
+EOF
+
+csplit -f .newmeson_options meson_options.txt 
"/#PLACEHOLDER_NEWPROG_MESON_OPTION_START/+1" 
"/#PLACEHOLDER_NEWPROG_MESON_OPTION_END/"
+echo "option('config_${PROGRAMMERNAME}', type : 'boolean', value : true, 
description : '${PROGRAMMERDESCR}')" >>.newmeson_options01
+sort .newmeson_options01 >.newmeson_options03
+cat .newmeson_options00 .newmeson_options03 .newmeson_options02 
>meson_options.txt.mine
+rm .newmeson_options00 .newmeson_options01 .newmeson_options02 
.newmeson_options03
+
+csplit -f .newmeson meson.build 
"/#PLACEHOLDER_NEWPROG_MESON_CONFIGFETCH_START/+1" 
"/#PLACEHOLDER_NEWPROG_MESON_CONFIGFETCH_END/"
+echo "config_${PROGRAMMERNAME} = get_option('config_${PROGRAMMERNAME}')" 
>>.newmeson01
+sort .newmeson01 >.newmeson03
+cat .newmeson00 .newmeson03 .newmeson02 >.newmeson.build.mine
+rm .newmeson00 .newmeson01 .newmeson02 .newmeson03
+
+if test $DEVICETYPE = PCI ; then
+       csplit -f .newmeson .newmeson.build.mine 
"/#PLACEHOLDER_NEWPROG_MESON_PCI_REQUIREMENT_MISSING_START/+1" 
"/#PLACEHOLDER_NEWPROG_MESON_PCI_REQUIREMENT_MISSING_END/"
+       echo "  config_${PROGRAMMERNAME} = false" >>.newmeson01
+       sort .newmeson01 >.newmeson03
+       cat .newmeson00 .newmeson03 .newmeson02 >.newmeson.build.mine
+       rm .newmeson00 .newmeson01 .newmeson02 .newmeson03
+fi
+
+if test $DEVICETYPE = USB ; then
+       csplit -f .newmeson .newmeson.build.mine 
"/#PLACEHOLDER_NEWPROG_MESON_USB_REQUIREMENT_MISSING_START/+1" 
"/#PLACEHOLDER_NEWPROG_MESON_USB_REQUIREMENT_MISSING_END/"
+       echo "  config_${PROGRAMMERNAME} = false" >>.newmeson01
+       sort .newmeson01 >.newmeson03
+       cat .newmeson00 .newmeson03 .newmeson02 >.newmeson.build.mine
+       rm .newmeson00 .newmeson01 .newmeson02 .newmeson03
+fi
+
+csplit -f .newmeson .newmeson.build.mine 
"/#PLACEHOLDER_NEWPROG_MESON_FILES_DEFINES_NEEDS_START/+1" 
"/#PLACEHOLDER_NEWPROG_MESON_FILES_DEFINES_NEEDS_END/"
+# FIXME: The current meson.build always builds the PCI intrastructure unless 
explicitly disabled.
+cat >>.newmeson01 <<EOF
+if config_${PROGRAMMERNAME}
+  srcs += '${PROGRAMMERNAME}.c'
+  cargs += '-D${CONFIGNAME}=1'
+EOF
+if $NEED_SERIAL = yes; then
+       cat >>.newmeson01 <<EOF
+  need_serial = true
+EOF
+cat >>.newmeson01 <<EOF
+endif
+EOF
+# FIXME: Sorting is a bit more complicated here. Skip it for now.
+cat .newmeson00 .newmeson01 .newmeson02 >.newmeson.build.mine
+rm .newmeson00 .newmeson01 .newmeson02
+
+mv .newmeson.build.mine meson.build.mine
+
+echo "The driver skeleton has been created in $PROGRAMMERNAME.c.mine"
+echo "Modified versions of existing files have been created with extension 
.mine"
+echo "You can replace the original files with the modified versions by running"
+echo "for a in *; do test -f \$a.mine && mv \$a.mine \$a; done"
+echo "If you want to use the newly generated skeleton $PROGRAMMERNAME.c.mine , 
run"
+echo "mv $PROGRAMMERNAME.c.mine $PROGRAMMERNAME.c"
+echo
+echo "WARNING: Please note that rerunning build_new_driver.sh will overwrite"
+echo "all *.mine files, but it won't touch $PROGRAMMERNAME.c ."
+echo "If something goes wrong, you can revert all files which look odd and"
+echo "run this script again."
diff -r 7bf17529e516 flashchips.h
--- a/flashchips.h      Tue Dec 31 18:22:02 2019 +0100
+++ b/flashchips.h      Wed Jan 15 13:20:27 2020 +0100
@@ -602,7 +602,7 @@
 #define PMC_PM49FL004          0x6E

 /*
- * The Sanyo chip found so far uses SPI, first byte is manufacture code,
+ * The Sanyo chip found so far uses SPI, first byte is manufacturer code,
  * second byte is the device code,
  * third byte is a dummy byte.
  */
diff -r 7bf17529e516 flashrom.8.tmpl
--- a/flashrom.8.tmpl   Tue Dec 31 18:22:02 2019 +0100
+++ b/flashrom.8.tmpl   Wed Jan 15 13:20:27 2020 +0100
@@ -345,6 +345,9 @@
 .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 @@
 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 @@
 .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 -r 7bf17529e516 flashrom.c
--- a/flashrom.c        Tue Dec 31 18:22:02 2019 +0100
+++ b/flashrom.c        Wed Jan 15 13:20:27 2020 +0100
@@ -473,6 +473,19 @@
        },
 #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 -r 7bf17529e516 meson.build
--- a/meson.build       Tue Dec 31 18:22:02 2019 +0100
+++ b/meson.build       Wed Jan 15 13:20:27 2020 +0100
@@ -30,6 +30,7 @@
 add_project_arguments('-DFLASHROM_VERSION="' + meson.project_version() + '"', 
language : 'c')

 # get defaults from configure
+# PLACEHOLDER_NEWPROG_MESON_CONFIGFETCH_START
 config_atahpt = get_option('config_atahpt')
 config_atapromise = get_option('config_atapromise')
 config_atavia = get_option('config_atavia')
@@ -62,6 +63,7 @@
 config_serprog = get_option('config_serprog')
 config_usbblaster_spi = get_option('config_usbblaster_spi')
 config_stlinkv3_spi = get_option('config_stlinkv3_spi')
+# PLACEHOLDER_NEWPROG_MESON_CONFIGFETCH_END

 cargs = []
 deps = []
@@ -86,11 +88,13 @@
   srcs += 'usbdev.c'
   deps += dependency('libusb-1.0')
 else
+# PLACEHOLDER_NEWPROG_MESON_USB_REQUIREMENT_MISSING_START
   config_ch341a_spi = false
   config_dediprog = false
   config_digilent_spi = false
   config_developerbox_spi = false
   config_pickit2_spi = false
+# PLACEHOLDER_NEWPROG_MESON_USB_REQUIREMENT_MISSING_END
 endif

 # some programmers require libpci
@@ -99,6 +103,7 @@
   deps += dependency('libpci')
   cargs += '-DNEED_PCI=1'
 else
+# PLACEHOLDER_NEWPROG_MESON_PCI_REQUIREMENT_MISSING_START
   config_atahpt = false
   config_atapromise = false
   config_atavia = false
@@ -116,9 +121,11 @@
   config_rayer_spi = false
   config_satamv = false
   config_satasii = false
+# PLACEHOLDER_NEWPROG_MESON_PCI_REQUIREMENT_MISSING_END
 endif

 # set defines for configured programmers
+# PLACEHOLDER_NEWPROG_MESON_FILES_DEFINES_NEEDS_START
 if config_atahpt
   srcs += 'atahpt.c'
   cargs += '-DCONFIG_ATAHPT=1'
@@ -276,6 +283,7 @@
   srcs += 'stlinkv3_spi.c'
   cargs += '-DCONFIG_STLINKV3_SPI=1'
 endif
+# PLACEHOLDER_NEWPROG_MESON_FILES_DEFINES_NEEDS_END

 # bitbanging SPI infrastructure
 if config_bitbang_spi
diff -r 7bf17529e516 meson_options.txt
--- a/meson_options.txt Tue Dec 31 18:22:02 2019 +0100
+++ b/meson_options.txt Wed Jan 15 13:20:27 2020 +0100
@@ -1,6 +1,7 @@
 option('pciutils', type : 'boolean', value : true, description : 'use 
pciutils')
 option('usb', type : 'boolean', value : true, description : 'use libusb1')

+#PLACEHOLDER_NEWPROG_MESON_OPTION_START
 option('config_atahpt', type : 'boolean', value : false, description : 
'Highpoint (HPT) ATA/RAID controllers')
 option('config_atapromise', type : 'boolean', value : false, description : 
'Promise ATA controller')
 option('config_atavia', type : 'boolean', value : true, description : 'VIA 
VT6421A LPC memory')
@@ -33,3 +34,4 @@
 option('config_satasii', type : 'boolean', value : true, description : 'SiI 
SATA controllers')
 option('config_serprog', type : 'boolean', value : true, description : 
'serprog')
 option('config_usbblaster_spi', type : 'boolean', value : true, description : 
'Altera USB-Blaster dongles')
+#PLACEHOLDER_NEWPROG_MESON_OPTION_END
diff -r 7bf17529e516 pcidev.c
--- a/pcidev.c  Tue Dec 31 18:22:02 2019 +0100
+++ b/pcidev.c  Wed Jan 15 13:20:27 2020 +0100
@@ -148,33 +148,6 @@
        return (uintptr_t)addr;
 }

-static uintptr_t pcidev_validate(struct pci_dev *dev, int bar, const struct 
dev_entry *devs)
-{
-       unsigned i;
-
-       /* Check against list of supported devices. */
-       for (i = 0; devs[i].device_name != NULL; i++) {
-               if (dev->device_id != devs[i].device_id)
-                       continue;
-
-               msg_pinfo("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n",
-                               devs[i].vendor_name, devs[i].device_name,
-                               dev->vendor_id, dev->device_id, dev->bus, 
dev->dev,
-                               dev->func);
-
-               if (devs[i].status == NT)
-                       msg_pinfo("===\nThis PCI device is UNTESTED. Please 
report the 'flashrom -p "
-                                 "xxxx' output\n"
-                                 "to flashrom@flashrom.org if it works for 
you. Please add the name "
-                                 "of your\n"
-                                 "PCI device to the subject. Thank you for 
your help!\n===\n");
-
-
-               return pcidev_readbar(dev, bar);
-       }
-       return 0;
-}
-
 static int pcidev_shutdown(void *data)
 {
        if (pacc == NULL) {
@@ -210,10 +183,12 @@
 struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar)
 {
        struct pci_dev *dev;
+       struct pci_dev *found_dev = NULL;
        struct pci_filter filter;
        char *pcidev_bdf;
        char *msg = NULL;
        int found = 0;
+       int i;
        uintptr_t addr = 0;

        if (pci_init_common() != 0)
@@ -232,10 +207,30 @@

        for (dev = pacc->devices; dev; dev = dev->next) {
                if (pci_filter_match(&filter, dev)) {
+                       /* Check against list of supported devices. */
+                       for (i = 0; devs[i].device_name != NULL; i++)
+                               if ((dev->vendor_id == devs[i].vendor_id) &&
+                                   (dev->device_id == devs[i].device_id))
+                                       break;
+                       /* Not supported, try the next one. */
+                       if (devs[i].device_name == NULL)
+                               continue;
+
+                       msg_pdbg("Found \"%s %s\" (%04x:%04x, BDF 
%02x:%02x.%x).\n", devs[i].vendor_name,
+                                devs[i].device_name, dev->vendor_id, 
dev->device_id, dev->bus, dev->dev,
+                                dev->func);
+                       if (devs[i].status == NT)
+                               msg_pinfo("===\nThis PCI device is UNTESTED. 
Please report the 'flashrom -p "
+                                         "xxxx' output\n"
+                                         "to flashrom@flashrom.org if it works 
for you. Please add the name "
+                                         "of your\n"
+                                         "PCI device to the subject. Thank you 
for your help!\n===\n");
+
                        /* FIXME: We should count all matching devices, not
                         * just those with a valid BAR.
                         */
-                       if ((addr = pcidev_validate(dev, bar, devs)) != 0) {
+                       if ((addr = pcidev_readbar(dev, bar)) != 0) {
+                               found_dev = dev;
                                found++;
                        }
                }
@@ -251,7 +246,7 @@
                return NULL;
        }

-       return dev;
+       return found_dev;
 }

 enum pci_write_type {
diff -r 7bf17529e516 programmer.h
--- a/programmer.h      Tue Dec 31 18:22:02 2019 +0100
+++ b/programmer.h      Wed Jan 15 13:20:27 2020 +0100
@@ -127,6 +127,10 @@
 #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 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 -r 7bf17529e516 vl805.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/vl805.c   Wed Jan 15 13:20:27 2020 +0100
@@ -0,0 +1,171 @@
+/*
+ * 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 "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_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(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++) {
+                       readarr[j + i] = indata & 0xff;
+                       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,
+};
+
+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. */
+       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);
+       if (val != 0x00000200) {
+               msg_perr("VL805_REG_0x30004 returned unexpected value 
0x%08x\n", val);
+               return 1;
+       }
+       vl805_setregval(VL805_REG_0x30004, 0x00000200);
+       val = vl805_getregval(VL805_REG_WB_EN);
+       if (val != 0xffffffff) {
+               msg_perr("VL805_REG_WB_EN returned unexpected value 0x%08x\n", 
val);
+               return 1;
+       }
+       vl805_setregval(VL805_REG_WB_EN, 0xffffff01);
+       val = vl805_getregval(VL805_REG_STOP_POLLING);
+       if (val != 0x00000001) {
+               msg_perr("VL805_REG_STOP_POLLING returned unexpected value 
0x%08x\n", val);
+               return 1;
+       }
+       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);
+
+       return 0;
+}
_______________________________________________
flashrom mailing list -- flashrom@flashrom.org
To unsubscribe send an email to flashrom-le...@flashrom.org

Reply via email to