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.2006@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; +}