Nick: carldani E-mail: c-d.hailfinger.devel.2006@gmx.net Board: vl805 patch incl programmer driver writer Contents: diff -r 5a19d449e4f6 Makefile --- a/Makefile Sat Jan 18 18:23:22 2020 +0000 +++ b/Makefile Mon Jan 20 01:12:18 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 5a19d449e4f6 atavia.c --- a/atavia.c Sat Jan 18 18:23:22 2020 +0000 +++ b/atavia.c Mon Jan 20 01:12:18 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 5a19d449e4f6 build_new_driver.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build_new_driver.sh Mon Jan 20 01:12:18 2020 +0100 @@ -0,0 +1,420 @@ +#!/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 <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine < +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, + .write_aai = default_spi_write_aai, +}; + +EOF +fi + +cat >>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>.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 <>.newmeson01 <>.newmeson01 <.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 5a19d449e4f6 flashchips.h --- a/flashchips.h Sat Jan 18 18:23:22 2020 +0000 +++ b/flashchips.h Mon Jan 20 01:12:18 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 5a19d449e4f6 flashrom.8.tmpl --- a/flashrom.8.tmpl Sat Jan 18 18:23:22 2020 +0000 +++ b/flashrom.8.tmpl Mon Jan 20 01:12:18 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 5a19d449e4f6 flashrom.c --- a/flashrom.c Sat Jan 18 18:23:22 2020 +0000 +++ b/flashrom.c Mon Jan 20 01:12:18 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 5a19d449e4f6 meson.build --- a/meson.build Sat Jan 18 18:23:22 2020 +0000 +++ b/meson.build Mon Jan 20 01:12:18 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 5a19d449e4f6 meson_options.txt --- a/meson_options.txt Sat Jan 18 18:23:22 2020 +0000 +++ b/meson_options.txt Mon Jan 20 01:12:18 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 5a19d449e4f6 programmer.h --- a/programmer.h Sat Jan 18 18:23:22 2020 +0000 +++ b/programmer.h Mon Jan 20 01:12:18 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 5a19d449e4f6 vl805.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vl805.c Mon Jan 20 01:12:18 2020 +0100 @@ -0,0 +1,188 @@ +/* + * 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); + 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. */ + 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) { + /* Not an error since the code can handle it and different values have appeared in different + * traces, but I'd rather see the message reported. + * */ + msg_perr("VL805_REG_0x30004 returned unexpected value 0x%08x\n", val); + } + val &= 0xffff00ff; + /* Some traces also write a value of 0x0300 to this register. */ + val |= 0x0200; + vl805_setregval(VL805_REG_0x30004, val); + + val = vl805_getregval(VL805_REG_WB_EN); + if (val != 0xffffffff) { + /* I haven't seen a different value yet, so complain and abort. */ + msg_perr("VL805_REG_WB_EN returned unexpected value 0x%08x\n", val); + return 1; + } + val &= 0xffffff00; + val |= 0x01; + vl805_setregval(VL805_REG_WB_EN, val); + + val = vl805_getregval(VL805_REG_STOP_POLLING); + if (val != 0x00000001) { + /* I haven't seen a different value yet, so complain and abort. */ + msg_perr("VL805_REG_STOP_POLLING returned unexpected value 0x%08x\n", val); + return 1; + } + val &= 0xffffff00; + val |= 0x01; + vl805_setregval(VL805_REG_STOP_POLLING, val); + + /* 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; +}