Nick: carldani E-mail: c-d.hailfinger.devel.2006@gmx.net Board: vl805 patch 3 Contents: diff -r 7bf17529e516 -r cf09d9d0ff90 Makefile --- a/Makefile Tue Dec 31 18:22:02 2019 +0100 +++ b/Makefile Thu Jan 09 13:50:50 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 -r cf09d9d0ff90 build_new_driver.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build_new_driver.sh Thu Jan 09 13:50:50 2020 +0100 @@ -0,0 +1,354 @@ +#!/bin/bash +# flashrom programmer driver skeleton builder. +# Copyright 2012 Carl-Daniel Hailfinger +# Licensed under the GNU GPL v2 + +# 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=ezo +# Short description of the programmer. Please do not use / inside the name, it will break the sed expressions. +PROGRAMMERDESCR="EZo+Willem Programmer" +# Name of the programmer manufacturer. +PROGRAMMERMANUF="EZo and Willem" +# Website for the programmer. +PROGRAMMERURL="http://www.ezoflash.com/" +# Fill in your name here. +AUTHORNAME="Carl-Daniel Hailfinger" +# 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=USB +# 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=yes +# Which of PARALLEL/LPC/FWH buses does the programer use? +BUS_PARLPCFWH=LPC +# Does the programmer use SPI functionality without bitbanging? +NEED_SPI=yes +# Does the programmer use the bitbanging SPI infrastructure? +NEED_SPI_BITBANG=yes + +# No user serviceable parts below. +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, +}; + +EOF +fi + +cat >>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine <>$PROGRAMMERNAME.c.mine < 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); + 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 int vl805_jedec_rems(void) +{ + /* Run JEDEC_REMS. TODO: Make this a generic SPI command function. */ + uint32_t val; + uint32_t outdata = JEDEC_REMS << 24 | (0); + + vl805_setregval(VL805_REG_SPI_CHIP_ENABLE_LEVEL, 0x00000000); + vl805_setregval(VL805_REG_SPI_OUTDATA, outdata); + vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x00000580 | 0x40); + val = vl805_getregval(VL805_REG_SPI_INDATA); + msg_pdbg("REMS response is 0x%08x\n", val); + if (val != 0xef10ef10) + return 1; + vl805_setregval(VL805_REG_SPI_CHIP_ENABLE_LEVEL, 0x00000001); + return 0; +} + +static void vl805_programmer_active(uint8_t val) +{ + pci_write_byte(dev, 67, val); +} + +static int vl805_shutdown(void *data) +{ + /* Shutdown stuff. */ + vl805_programmer_active(0x0); + return 0; +} + +int vl805_init(void) +{ + /* Init stuff (i.e. parameter parsing) here which does not need to be + * undone. + */ + if (rget_io_perms()) + return 1; + + dev = pcidev_init(ata_via, PCI_ROM_ADDRESS); /* FIXME typo Acutally no BAR setup needed at all. */ + if (!dev) + return 1; + + vl805_programmer_active(0x1); + uint32_t val = pci_read_long(dev, 80); + 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_0x40020); + if (val != 0xffffffff) { + msg_perr("VL805_REG_0x40020 returned unexpected value 0x%08x\n", val); + return 1; + } + vl805_setregval(VL805_REG_0x40020, 0xffffff01); + val = vl805_getregval(VL805_REG_0x4000c); + if (val != 0x00000001) { + msg_perr("VL805_REG_0x4000c returned unexpected value 0x%08x\n", val); + return 1; + } + vl805_setregval(VL805_REG_0x4000c, 0x00000001); + vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x000005a0); + vl805_setregval(VL805_REG_0x400f8, 0x0000000a); + + /* Run JEDEC_REMS */ + if (vl805_jedec_rems()) + return 1; + + /* Some sort of cleanup sequence, just copied from the logs. */ + vl805_setregval(VL805_REG_SPI_TRANSACTION, 0x00000000); + vl805_programmer_active(0x0); + + /* If your shutdown function takes a parameter, replace NULL with it. */ + register_shutdown(vl805_shutdown, NULL); + vl805_programmer_active(0x1); + + /* Init stuff which needs to be undone on shutdown. */ + + register_spi_master(&spi_master_vl805); + + /* Return an error for now. */ + return 1; +}