hi --
this patch adds support for a new SPI programmer, based on the FT22/4232H chip from FTDI. the chip is used in what is essentially a USB-to-SPI converter mode. carl-daniel and i have passed the code back and forth a couple of times, so it's a joint effort.
the change introduces new dependencies on libftdi and libusb. in addition, the latest libftdi code from: http://www.intra2net.com/en/developer/libftdi must be used -- certainly the current ubuntu version is out of date. (btw, the easiest way to use the latest, since libftdi is just one C source file, is simply to copy ftdi.c/h into the flashrom build dir, and modify the makefile to add ftdi.o to the source list.)
there are certainly possible improvements: the code has hard-coded values for which interface of the ftdi chip to use (interface B was chosen because libftdi seems to have trouble with A right now), what clock rate use for the SPI interface (i've been running at 30Mhz, but the patch sets it to 10Mhz), and possibly others. i think this means that per-programmer options might be a good idea at some point.
there are also flashrom oddities like seeing a meaningless physical address for the flash, seeing probing happen for multiple chips, etc. carl-daniel tells me there is new spi infrastructure in the works that might address some of this.
paul =--------------------- paul fox, pgf@foxharp.boston.ma.us (arlington, ma, where it's 55.6 degrees)
Signed-off-by: Paul Fox pgf@laptop.org
Index: flash.h =================================================================== --- flash.h (revision 581) +++ flash.h (working copy) @@ -85,6 +85,7 @@ #define PROGRAMMER_NIC3COM 0x02 #define PROGRAMMER_SATASII 0x03 #define PROGRAMMER_IT87SPI 0x04 +#define PROGRAMMER_FT2232SPI 0x05
struct programmer_entry { const char *vendor; @@ -707,6 +708,13 @@ uint8_t satasii_chip_readb(const chipaddr addr); extern struct pcidev_status satas_sii[];
+/* ft2232_spi.c */ +int ft2232_spi_init(void); +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf); +int ft2232_spi_write1(struct flashchip *flash, uint8_t *buf); +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf); + /* flashrom.c */ extern int verbose; #define printf_debug(x...) { if (verbose) printf(x); } @@ -733,6 +741,7 @@ SPI_CONTROLLER_SB600, SPI_CONTROLLER_VIA, SPI_CONTROLLER_WBSIO, + SPI_CONTROLLER_FT2232, SPI_CONTROLLER_DUMMY, }; extern enum spi_controller spi_controller; @@ -757,6 +766,7 @@ uint8_t spi_read_status_register(void); int spi_disable_blockprotect(void); void spi_byte_program(int address, uint8_t byte); +int spi_nbyte_program(int address, uint8_t *bytes, int len); int spi_nbyte_read(int address, uint8_t *bytes, int len); int spi_aai_write(struct flashchip *flash, uint8_t *buf); uint32_t spi_get_valid_read_addr(void); Index: spi.c =================================================================== --- spi.c (revision 581) +++ spi.c (working copy) @@ -46,6 +46,8 @@ return sb600_spi_command(writecnt, readcnt, writearr, readarr); case SPI_CONTROLLER_WBSIO: return wbsio_spi_command(writecnt, readcnt, writearr, readarr); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_command(writecnt, readcnt, writearr, readarr); case SPI_CONTROLLER_DUMMY: return dummy_spi_command(writecnt, readcnt, writearr, readarr); default: @@ -211,6 +213,7 @@ case SPI_CONTROLLER_VIA: case SPI_CONTROLLER_SB600: case SPI_CONTROLLER_WBSIO: + case SPI_CONTROLLER_FT2232: case SPI_CONTROLLER_DUMMY: return probe_spi_rdid_generic(flash, 4); default: @@ -616,6 +619,27 @@ spi_command(sizeof(cmd), 0, cmd, NULL); }
+int spi_nbyte_program(int address, uint8_t *bytes, int len) +{ + unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = { + JEDEC_BYTE_PROGRAM, + (address >> 16) & 0xff, + (address >> 8) & 0xff, + (address >> 0) & 0xff, + }; + + if (len > 256) { + printf_debug ("%s called for too long a write\n", + __FUNCTION__); + return 1; + } + + memcpy(&cmd[4], bytes, len); + + /* Send Byte-Program */ + return spi_command(4 + len, 0, cmd, NULL); +} + int spi_disable_blockprotect(void) { uint8_t status; @@ -665,6 +689,8 @@ return ich_spi_read(flash, buf); case SPI_CONTROLLER_WBSIO: return wbsio_spi_read(flash, buf); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_read(flash, buf); default: printf_debug ("%s called, but no SPI chipset/strapping detected\n", @@ -713,6 +739,8 @@ return ich_spi_write_256(flash, buf); case SPI_CONTROLLER_WBSIO: return wbsio_spi_write_1(flash, buf); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_write_256(flash, buf); default: printf_debug ("%s called, but no SPI chipset/strapping detected\n", Index: Makefile =================================================================== --- Makefile (revision 581) +++ Makefile (working copy) @@ -26,7 +26,7 @@ LDFLAGS += -L/usr/local/lib endif
-LIBS += -lpci -lz +LIBS += -lpci -lz -lftdi
OBJS = chipset_enable.o board_enable.o udelay.o jedec.o stm50flw0x0x.o \ sst28sf040.o am29f040b.o mx29f002.o m29f400bt.o \ @@ -34,7 +34,7 @@ sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \ flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \ ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \ - dummyflasher.o pcidev.o nic3com.o satasii.o + dummyflasher.o pcidev.o nic3com.o satasii.o ft2232_spi.o
all: pciutils dep $(PROGRAM)
Index: ft2232_spi.c =================================================================== --- ft2232_spi.c (revision 0) +++ ft2232_spi.c (revision 0) @@ -0,0 +1,263 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Paul Fox pgf@laptop.org + * Copyright (C) 2009 Carl-Daniel Hailfinger + * + * based initially on example program bitbang_ft2232.c from + * the libftdi-0.16 distribution, from: + * Intra2net AG opensource@intra2net.com + * + * 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 + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include "ftdi.h" +#include "flash.h" +#include "spi.h" + +/* the 'H' chips can run internally at either 12Mhz or 60Mhz. + * the non-H chips can only run at 12Mhz. */ +#define CLOCK_5X 1 + +/* in either case, the divisor is a simple integer clock divider. + * if CLOCK_5X is set, this divisor divides 30Mhz, else it + * divides 6Mhz */ +#define DIVIDE_BY 3 // e.g. '3' will give either 10Mhz or 2Mhz spi clock + + +static struct ftdi_context ftdic_context; + +int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_write_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_write_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + +int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_read_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_read_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + + +int ft2232_spi_init(void) +{ + int f; + struct ftdi_context *ftdic = &ftdic_context; + unsigned char buf[512]; + unsigned char port_val = 0; + + + if (ftdi_init(ftdic) < 0) { + fprintf(stderr, "ftdi_init failed\n"); + return EXIT_FAILURE; + } + + // f = ftdi_usb_open(ftdic, 0x0403, 0x6010); // FT2232 + f = ftdi_usb_open(ftdic, 0x0403, 0x6011); // FT4232 + + if (f < 0 && f != -5) { + fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f, + ftdi_get_error_string(ftdic)); + exit(-1); + } + + if (ftdi_set_interface(ftdic, INTERFACE_B) < 0) { + fprintf(stderr, "unable to select FT2232 channel B: %s\n", + ftdic->error_str); + } + + if (ftdi_usb_reset(ftdic) < 0) { + fprintf(stderr, "unable to reset ftdi device\n"); + } + + if (ftdi_set_latency_timer(ftdic, 2) < 0) { + fprintf(stderr, "unable to set latency timer\n"); + } + + if (ftdi_write_data_set_chunksize(ftdic, 512)) { + fprintf(stderr, "unable to set chunk size\n"); + } + + if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) { + fprintf(stderr, "unable to set bitmode\n"); + } + +#if CLOCK_5X + printf_debug("disable divide-by-5 front stage\n"); + buf[0] = 0x8a; /* disable divide-by-5 */ + if (send_buf(ftdic, buf, 1)) + return -1; +#define MPSSE_CLK 60.0 + +#else + +#define MPSSE_CLK 12.0 + +#endif + printf_debug("set clock divisor\n"); + buf[0] = 0x86; /* command "set divisor" */ + /* valueL/valueH are (desired_divisor - 1) */ + buf[1] = (DIVIDE_BY-1) & 0xff; + buf[2] = ((DIVIDE_BY-1) >> 8) & 0xff; + if (send_buf(ftdic, buf, 3)) + return -1; + + printf("spi clock is %fMhz\n", + (double)(MPSSE_CLK / (((DIVIDE_BY-1) + 1) * 2))); + + /* Disconnect TDI/DO to TDO/DI for Loopback */ + printf_debug("no loopback of tdi/do tdo/di\n"); + buf[0] = 0x85; + if (send_buf(ftdic, buf, 1)) + return -1; + + printf_debug("set data bits\n"); + /* Set data bits low-byte command: + * value: 0x08 CS=high, DI=low, DO=low, SK=low + * dir: 0x0b CS=output, DI=input, DO=output, SK=output + */ +#define CS_BIT 0x08 + + buf[0] = SET_BITS_LOW; + buf[1] = (port_val = CS_BIT); + buf[2] = 0x0b; + if (send_buf(ftdic, buf, 3)) + return -1; + + printf_debug("\nft2232 chosen\n"); + + buses_supported = CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_FT2232; + + return 0; +} + +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + struct ftdi_context *ftdic = &ftdic_context; + static unsigned char *buf; + unsigned char port_val = 0; + int i, ret = 0; + + buf = realloc(buf, writecnt + readcnt + 100); + + i = 0; + + /* minimize USB transfers by packing as many commands + * as possible together. if we're not expecting to + * read, we can assert CS, write, and deassert CS all + * in one shot. if reading, we do three separate + * operations. */ + printf_debug("Assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = (port_val &= ~CS_BIT); + buf[i++] = 0x0b; + + if (writecnt) { + buf[i++] = 0x11; + buf[i++] = (writecnt - 1) & 0xff; + buf[i++] = ((writecnt - 1) >> 8) & 0xff; + memcpy(buf+i, writearr, writecnt); + i += writecnt; + } + + /* optionally terminate this batch of commands with a + * read command, then do the fetch of the results. + */ + if (readcnt) { + buf[i++] = 0x20; + buf[i++] = (readcnt - 1) & 0xff; + buf[i++] = ((readcnt - 1) >> 8) & 0xff; + ret = send_buf(ftdic, buf, i); + i = 0; + if (ret) goto deassert_cs; + + ret = get_buf(ftdic, readarr, readcnt); + + } + + deassert_cs: + printf_debug("de-assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = (port_val |= CS_BIT); + buf[i++] = 0x0b; + if (send_buf(ftdic, buf, i)) + return -1; + + return ret; +} + +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf) +{ + int total_size = flash->total_size * 1024; + int i, n; + + /* the ft2232/ft4232 will transfer up to 64K at a time */ + n = 64 * 1024; + for (i = 0; i < total_size; i += n) { + int toread = n; + if (total_size - i < toread) + toread = total_size - i; + spi_nbyte_read(i, buf + i, toread); + } + + return 0; +} + + +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) +{ + int total_size = 1024 * flash->total_size; + int i; + + printf_debug("total_size is %d\n", total_size); + for (i = 0; i < total_size; i += 256) { + int l, r; + if (i + 256 <= total_size) + l = 256; + else + l = total_size - i; + + spi_write_enable(); + if ((r = spi_nbyte_program(i, &buf[i], l))) { + fprintf(stderr, "%s: write fail %d\n", __FUNCTION__, r); + // spi_write_disable(); chip does this for us + return 1; + } + + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + /* loop */; + } + // spi_write_disable(); chip does this for us + + return 0; +} + Index: flashrom.c =================================================================== --- flashrom.c (revision 581) +++ flashrom.c (working copy) @@ -115,6 +115,22 @@ .delay = internal_delay, },
+ { + .init = ft2232_spi_init, + .shutdown = dummy_shutdown, + .map_flash_region = dummy_map, + .unmap_flash_region = dummy_unmap, + .chip_readb = dummy_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = dummy_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, + {}, };
@@ -495,7 +511,7 @@ " -i | --image <name>: only flash image name from flash layout\n" " -L | --list-supported: print supported devices\n" " -p | --programmer <name>: specify the programmer device\n" - " (internal, dummy, nic3com, satasii, it87spi)\n" + " (internal, dummy, nic3com, satasii, it87spi, ft2232spi)\n" " -h | --help: print this help text\n" " -R | --version: print the version (release)\n" "\nIf no file is specified, then all that happens" @@ -631,6 +647,8 @@ pcidev_bdf = strdup(optarg + 8); } else if (strncmp(optarg, "it87spi", 7) == 0) { programmer = PROGRAMMER_IT87SPI; + } else if (strncmp(optarg, "ft2232spi", 9) == 0) { + programmer = PROGRAMMER_FT2232SPI; } else { printf("Error: Unknown programmer.\n"); exit(1); @@ -820,11 +838,13 @@ // ////////////////////////////////////////////////////////////
if (write_it) { + printf("Writing flash chip... "); if (!flash->write) { fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n"); return 1; } ret |= flash->write(flash, buf); + if (!ret) printf("COMPLETE.\n"); }
if (verify_it)
On 11.06.2009 21:00, Paul Fox wrote:
this patch adds support for a new SPI programmer, based on the FT22/4232H chip from FTDI.
Signed-off-by: Paul Fox pgf@laptop.org
Thanks for the patch.
I've split out a few hunks and commited them separately: - printing start and end of the write operation (r582) - the new spi_nbyte_program function in the SPI layer (r583).
Both parts were your work only, so I felt comfortable to ack and commit them.
I'll repost the rest of this patch in a few minutes.
Regards, Carl-Daniel
This patch adds support for a new SPI programmer, based on the FT2232H/4232H chip from FTDI.
Until we have a solution for the compilation/linking dependency on libftdi, support for this feature is stubbed out by default. This allows us to commit the code now and work on a solution later.
Paul writes: There are certainly possible improvements: The code has hard-coded values for which interface of the ftdi chip to use (interface B was chosen because libftdi seems to have trouble with A right now), what clock rate use for the SPI interface (I've been running at 30Mhz, but the patch sets it to 10Mhz), and possibly others. I think this means that per-programmer options might be a good idea at some point.
Carl-Daniel writes: There is one additional FIXME comment in the code, but AFAICS that problem is not solvable with current libftdi.
Signed-off-by: Paul Fox pgf@laptop.org Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-ftdi2232_spi/flash.h =================================================================== --- flashrom-ftdi2232_spi/flash.h (Revision 583) +++ flashrom-ftdi2232_spi/flash.h (Arbeitskopie) @@ -85,6 +85,7 @@ #define PROGRAMMER_NIC3COM 0x02 #define PROGRAMMER_SATASII 0x03 #define PROGRAMMER_IT87SPI 0x04 +#define PROGRAMMER_FT2232SPI 0x05
struct programmer_entry { const char *vendor; @@ -707,6 +708,13 @@ uint8_t satasii_chip_readb(const chipaddr addr); extern struct pcidev_status satas_sii[];
+/* ft2232_spi.c */ +int ft2232_spi_init(void); +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf); +int ft2232_spi_write1(struct flashchip *flash, uint8_t *buf); +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf); + /* flashrom.c */ extern int verbose; #define printf_debug(x...) { if (verbose) printf(x); } @@ -733,6 +741,7 @@ SPI_CONTROLLER_SB600, SPI_CONTROLLER_VIA, SPI_CONTROLLER_WBSIO, + SPI_CONTROLLER_FT2232, SPI_CONTROLLER_DUMMY, }; extern enum spi_controller spi_controller; Index: flashrom-ftdi2232_spi/spi.c =================================================================== --- flashrom-ftdi2232_spi/spi.c (Revision 583) +++ flashrom-ftdi2232_spi/spi.c (Arbeitskopie) @@ -46,6 +46,8 @@ return sb600_spi_command(writecnt, readcnt, writearr, readarr); case SPI_CONTROLLER_WBSIO: return wbsio_spi_command(writecnt, readcnt, writearr, readarr); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_command(writecnt, readcnt, writearr, readarr); case SPI_CONTROLLER_DUMMY: return dummy_spi_command(writecnt, readcnt, writearr, readarr); default: @@ -211,6 +213,7 @@ case SPI_CONTROLLER_VIA: case SPI_CONTROLLER_SB600: case SPI_CONTROLLER_WBSIO: + case SPI_CONTROLLER_FT2232: case SPI_CONTROLLER_DUMMY: return probe_spi_rdid_generic(flash, 4); default: @@ -686,6 +689,8 @@ return ich_spi_read(flash, buf); case SPI_CONTROLLER_WBSIO: return wbsio_spi_read(flash, buf); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_read(flash, buf); default: printf_debug ("%s called, but no SPI chipset/strapping detected\n", @@ -734,6 +739,8 @@ return ich_spi_write_256(flash, buf); case SPI_CONTROLLER_WBSIO: return wbsio_spi_write_1(flash, buf); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_write_256(flash, buf); default: printf_debug ("%s called, but no SPI chipset/strapping detected\n", Index: flashrom-ftdi2232_spi/Makefile =================================================================== --- flashrom-ftdi2232_spi/Makefile (Revision 583) +++ flashrom-ftdi2232_spi/Makefile (Arbeitskopie) @@ -34,7 +34,7 @@ sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \ flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \ ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \ - dummyflasher.o pcidev.o nic3com.o satasii.o + dummyflasher.o pcidev.o nic3com.o satasii.o ft2232_spi.o
all: pciutils dep $(PROGRAM)
Index: flashrom-ftdi2232_spi/ft2232_spi.c =================================================================== --- flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) +++ flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) @@ -0,0 +1,303 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Paul Fox pgf@laptop.org + * Copyright (C) 2009 Carl-Daniel Hailfinger + * + * based initially on example program bitbang_ft2232.c from + * the libftdi-0.16 distribution, from: + * Intra2net AG opensource@intra2net.com + * + * 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 + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include "flash.h" +#include "spi.h" + +/* If you want FT2232 SPI support, please add -lftdi to LIBS in the Makefile + * and change FT2232_SPI_SUPPORT to 1 in the following line. + */ +#define FT2232_SPI_SUPPORT 0 +#if FT2232_SPI_SUPPORT == 1 + +#include "ftdi.h" + +/* the 'H' chips can run internally at either 12Mhz or 60Mhz. + * the non-H chips can only run at 12Mhz. */ +#define CLOCK_5X 1 + +/* in either case, the divisor is a simple integer clock divider. + * if CLOCK_5X is set, this divisor divides 30Mhz, else it + * divides 6Mhz */ +#define DIVIDE_BY 3 // e.g. '3' will give either 10Mhz or 2Mhz spi clock + + +static struct ftdi_context ftdic_context; + +int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_write_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_write_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + +int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_read_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_read_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + +int ft2232_spi_init(void) +{ + int f; + struct ftdi_context *ftdic = &ftdic_context; + unsigned char buf[512]; + unsigned char port_val = 0; + + + if (ftdi_init(ftdic) < 0) { + fprintf(stderr, "ftdi_init failed\n"); + return EXIT_FAILURE; + } + + // f = ftdi_usb_open(ftdic, 0x0403, 0x6010); // FT2232 + f = ftdi_usb_open(ftdic, 0x0403, 0x6011); // FT4232 + + if (f < 0 && f != -5) { + fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f, + ftdi_get_error_string(ftdic)); + exit(-1); + } + + if (ftdi_set_interface(ftdic, INTERFACE_B) < 0) { + fprintf(stderr, "unable to select FT2232 channel B: %s\n", + ftdic->error_str); + } + + if (ftdi_usb_reset(ftdic) < 0) { + fprintf(stderr, "unable to reset ftdi device\n"); + } + + if (ftdi_set_latency_timer(ftdic, 2) < 0) { + fprintf(stderr, "unable to set latency timer\n"); + } + + if (ftdi_write_data_set_chunksize(ftdic, 512)) { + fprintf(stderr, "unable to set chunk size\n"); + } + + if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) { + fprintf(stderr, "unable to set bitmode\n"); + } + +#if CLOCK_5X + printf_debug("disable divide-by-5 front stage\n"); + buf[0] = 0x8a; /* disable divide-by-5 */ + if (send_buf(ftdic, buf, 1)) + return -1; +#define MPSSE_CLK 60.0 + +#else + +#define MPSSE_CLK 12.0 + +#endif + printf_debug("set clock divisor\n"); + buf[0] = 0x86; /* command "set divisor" */ + /* valueL/valueH are (desired_divisor - 1) */ + buf[1] = (DIVIDE_BY-1) & 0xff; + buf[2] = ((DIVIDE_BY-1) >> 8) & 0xff; + if (send_buf(ftdic, buf, 3)) + return -1; + + printf("spi clock is %fMhz\n", + (double)(MPSSE_CLK / (((DIVIDE_BY-1) + 1) * 2))); + + /* Disconnect TDI/DO to TDO/DI for Loopback */ + printf_debug("no loopback of tdi/do tdo/di\n"); + buf[0] = 0x85; + if (send_buf(ftdic, buf, 1)) + return -1; + + printf_debug("set data bits\n"); + /* Set data bits low-byte command: + * value: 0x08 CS=high, DI=low, DO=low, SK=low + * dir: 0x0b CS=output, DI=input, DO=output, SK=output + */ +#define CS_BIT 0x08 + + buf[0] = SET_BITS_LOW; + buf[1] = (port_val = CS_BIT); + buf[2] = 0x0b; + if (send_buf(ftdic, buf, 3)) + return -1; + + printf_debug("\nft2232 chosen\n"); + + buses_supported = CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_FT2232; + + return 0; +} + +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + struct ftdi_context *ftdic = &ftdic_context; + static unsigned char *buf = NULL; + unsigned char port_val = 0; + int i, ret = 0; + + buf = realloc(buf, writecnt + readcnt + 100); + if (!buf) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + + i = 0; + + /* minimize USB transfers by packing as many commands + * as possible together. if we're not expecting to + * read, we can assert CS, write, and deassert CS all + * in one shot. if reading, we do three separate + * operations. */ + printf_debug("Assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = (port_val &= ~CS_BIT); + buf[i++] = 0x0b; + + if (writecnt) { + buf[i++] = 0x11; + buf[i++] = (writecnt - 1) & 0xff; + buf[i++] = ((writecnt - 1) >> 8) & 0xff; + memcpy(buf+i, writearr, writecnt); + i += writecnt; + } + + /* optionally terminate this batch of commands with a + * read command, then do the fetch of the results. + */ + if (readcnt) { + buf[i++] = 0x20; + buf[i++] = (readcnt - 1) & 0xff; + buf[i++] = ((readcnt - 1) >> 8) & 0xff; + ret = send_buf(ftdic, buf, i); + i = 0; + if (ret) goto deassert_cs; + + /* FIXME: This is unreliable. There's no guarantee that we read + * the response directly after sending the read command. + * We may be scheduled out etc. + */ + ret = get_buf(ftdic, readarr, readcnt); + + } + + deassert_cs: + printf_debug("de-assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = (port_val |= CS_BIT); + buf[i++] = 0x0b; + if (send_buf(ftdic, buf, i)) + return -1; + + return ret; +} + +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf) +{ + int total_size = flash->total_size * 1024; + int i, n; + + /* the ft2232/ft4232 will transfer up to 64K at a time */ + n = 64 * 1024; + for (i = 0; i < total_size; i += n) { + int toread = n; + if (total_size - i < toread) + toread = total_size - i; + spi_nbyte_read(i, buf + i, toread); + } + + return 0; +} + +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) +{ + int total_size = 1024 * flash->total_size; + int i; + + printf_debug("total_size is %d\n", total_size); + for (i = 0; i < total_size; i += 256) { + int l, r; + if (i + 256 <= total_size) + l = 256; + else + l = total_size - i; + + spi_write_enable(); + if ((r = spi_nbyte_program(i, &buf[i], l))) { + fprintf(stderr, "%s: write fail %d\n", __FUNCTION__, r); + // spi_write_disable(); chip does this for us + return 1; + } + + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + /* loop */; + } + // spi_write_disable(); chip does this for us + + return 0; +} + +#else +int ft2232_spi_init(void) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} + +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} + +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} + +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} +#endif Index: flashrom-ftdi2232_spi/flashrom.c =================================================================== --- flashrom-ftdi2232_spi/flashrom.c (Revision 583) +++ flashrom-ftdi2232_spi/flashrom.c (Arbeitskopie) @@ -115,6 +115,22 @@ .delay = internal_delay, },
+ { + .init = ft2232_spi_init, + .shutdown = dummy_shutdown, + .map_flash_region = dummy_map, + .unmap_flash_region = dummy_unmap, + .chip_readb = dummy_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = dummy_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, + {}, };
@@ -495,7 +511,7 @@ " -i | --image <name>: only flash image name from flash layout\n" " -L | --list-supported: print supported devices\n" " -p | --programmer <name>: specify the programmer device\n" - " (internal, dummy, nic3com, satasii, it87spi)\n" + " (internal, dummy, nic3com, satasii, it87spi, ft2232spi)\n" " -h | --help: print this help text\n" " -R | --version: print the version (release)\n" "\nIf no file is specified, then all that happens" @@ -631,6 +647,8 @@ pcidev_bdf = strdup(optarg + 8); } else if (strncmp(optarg, "it87spi", 7) == 0) { programmer = PROGRAMMER_IT87SPI; + } else if (strncmp(optarg, "ft2232spi", 9) == 0) { + programmer = PROGRAMMER_FT2232SPI; } else { printf("Error: Unknown programmer.\n"); exit(1);
On 12.06.2009 12:22, Carl-Daniel Hailfinger wrote:
This patch adds support for a new SPI programmer, based on the FT2232H/4232H chip from FTDI.
FTDI support is autodetected during compilation.
Paul writes: There are certainly possible improvements: The code has hard-coded values for which interface of the ftdi chip to use (interface B was chosen because libftdi seems to have trouble with A right now), what clock rate use for the SPI interface (I've been running at 30Mhz, but the patch sets it to 10Mhz), and possibly others. I think this means that per-programmer options might be a good idea at some point.
Carl-Daniel writes: There is one additional FIXME comment in the code, but AFAICS that problem is not solvable with current libftdi.
Signed-off-by: Paul Fox pgf@laptop.org Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
New in this version: - Adapted to handle partial reads - Autodetection of libftdi during compilation.
I think this patch is definitely committable. Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-ftdi2232_spi/flash.h =================================================================== --- flashrom-ftdi2232_spi/flash.h (Revision 597) +++ flashrom-ftdi2232_spi/flash.h (Arbeitskopie) @@ -86,6 +86,7 @@ #define PROGRAMMER_NIC3COM 0x02 #define PROGRAMMER_SATASII 0x03 #define PROGRAMMER_IT87SPI 0x04 +#define PROGRAMMER_FT2232SPI 0x05
struct programmer_entry { const char *vendor; @@ -358,6 +359,13 @@ uint8_t satasii_chip_readb(const chipaddr addr); extern struct pcidev_status satas_sii[];
+/* ft2232_spi.c */ +int ft2232_spi_init(void); +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int ft2232_spi_write1(struct flashchip *flash, uint8_t *buf); +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf); + /* flashrom.c */ extern int verbose; #define printf_debug(x...) { if (verbose) printf(x); } @@ -388,6 +396,7 @@ SPI_CONTROLLER_SB600, SPI_CONTROLLER_VIA, SPI_CONTROLLER_WBSIO, + SPI_CONTROLLER_FT2232, SPI_CONTROLLER_DUMMY, }; extern enum spi_controller spi_controller; Index: flashrom-ftdi2232_spi/spi.c =================================================================== --- flashrom-ftdi2232_spi/spi.c (Revision 597) +++ flashrom-ftdi2232_spi/spi.c (Arbeitskopie) @@ -47,6 +47,8 @@ return sb600_spi_command(writecnt, readcnt, writearr, readarr); case SPI_CONTROLLER_WBSIO: return wbsio_spi_command(writecnt, readcnt, writearr, readarr); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_command(writecnt, readcnt, writearr, readarr); case SPI_CONTROLLER_DUMMY: return dummy_spi_command(writecnt, readcnt, writearr, readarr); default: @@ -212,6 +214,7 @@ case SPI_CONTROLLER_VIA: case SPI_CONTROLLER_SB600: case SPI_CONTROLLER_WBSIO: + case SPI_CONTROLLER_FT2232: case SPI_CONTROLLER_DUMMY: return probe_spi_rdid_generic(flash, 4); default: @@ -726,6 +729,8 @@ return ich_spi_read(flash, buf, start, len); case SPI_CONTROLLER_WBSIO: return wbsio_spi_read(flash, buf, start, len); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_read(flash, buf, start, len); default: printf_debug ("%s called, but no SPI chipset/strapping detected\n", @@ -774,6 +779,8 @@ return ich_spi_write_256(flash, buf); case SPI_CONTROLLER_WBSIO: return wbsio_spi_write_1(flash, buf); + case SPI_CONTROLLER_FT2232: + return ft2232_spi_write_256(flash, buf); default: printf_debug ("%s called, but no SPI chipset/strapping detected\n", Index: flashrom-ftdi2232_spi/Makefile =================================================================== --- flashrom-ftdi2232_spi/Makefile (Revision 597) +++ flashrom-ftdi2232_spi/Makefile (Arbeitskopie) @@ -22,6 +22,7 @@ CC ?= gcc STRIP = strip INSTALL = install +DIFF = diff PREFIX ?= /usr/local MANDIR ?= $(PREFIX)/share/man CFLAGS ?= -Os -Wall -Werror @@ -48,9 +49,9 @@ sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \ flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \ ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \ - dummyflasher.o pcidev.o nic3com.o satasii.o + dummyflasher.o pcidev.o nic3com.o satasii.o ft2232_spi.o
-all: pciutils dep $(PROGRAM) +all: pciutils .features dep $(PROGRAM)
# Set the flashrom version string from the highest revision number # of the checked out flashrom files. @@ -63,16 +64,19 @@ SVNDEF := -D'FLASHROM_VERSION="$(VERSION)"'
$(PROGRAM): $(OBJS) - $(CC) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LIBS) + $(CC) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LIBS) $(FEATURE_LIBS)
flashrom.o: flashrom.c - $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< $(SVNDEF) + $(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURE_CFLAGS) -c -o $@ $< $(SVNDEF)
+%.o: %.c .features + $(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURE_CFLAGS) -c $< -o $@ + clean: rm -f $(PROGRAM) *.o
distclean: clean - rm -f .dependencies + rm -f .dependencies .features
dep: @$(CC) $(CPPFLAGS) $(SVNDEF) -MM *.c > .dependencies @@ -81,7 +85,7 @@ $(STRIP) $(STRIP_ARGS) $(PROGRAM)
compiler: - @echo; printf "Checking for a C compiler... " + @printf "Checking for a C compiler... " @$(shell ( echo "int main(int argc, char **argv)"; \ echo "{ return 0; }"; ) > .test.c ) @$(CC) $(CFLAGS) $(LDFLAGS) .test.c -o .test >/dev/null && \ @@ -89,8 +93,10 @@ rm -f .test.c .test; exit 1) @rm -f .test.c .test
-pciutils: compiler - @echo; printf "Checking for pciutils and zlib... " +# We don't specify compiler as requirement because the compiler is already +# checked during makefile remake through .features +pciutils: + @printf "Checking for pciutils and zlib... " @$(shell ( echo "#include <pci/pci.h>"; \ echo "struct pci_access *pacc;"; \ echo "int main(int argc, char **argv)"; \ @@ -102,6 +108,19 @@ rm -f .test.c .test; exit 1) @rm -f .test.c .test
+.features: compiler + @printf "Checking for FTDI support... " + @$(shell ( echo "#include <ftdi.h>"; \ + echo "struct ftdi_context *ftdic = NULL;"; \ + echo "int main(int argc, char **argv)"; \ + echo "{ return ftdi_init(ftdic); }"; ) > .featuretest.c ) + @$(CC) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest $(LIBS) -lftdi >/dev/null 2>&1 && \ + ( echo "found."; echo FEATURE_CFLAGS := -D'FT2232_SPI_SUPPORT=1' > .features.tmp; \ + echo FEATURE_LIBS := -lftdi >> .features.tmp) || \ + ( echo "not found."; echo "" > .features.tmp ) + @$(DIFF) -q .features.tmp .features >/dev/null 2>&1 && rm .features.tmp || mv .features.tmp .features + @rm -f .featuretest.c .featuretest + install: $(PROGRAM) mkdir -p $(DESTDIR)$(PREFIX)/sbin mkdir -p $(DESTDIR)$(MANDIR)/man8 @@ -122,3 +141,4 @@ .PHONY: all clean distclean dep compiler pciutils export tarball
-include .dependencies +-include .features Index: flashrom-ftdi2232_spi/ft2232_spi.c =================================================================== --- flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) +++ flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) @@ -0,0 +1,288 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Paul Fox pgf@laptop.org + * Copyright (C) 2009 Carl-Daniel Hailfinger + * + * based initially on example program bitbang_ft2232.c from + * the libftdi-0.16 distribution, from: + * Intra2net AG opensource@intra2net.com + * + * 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 + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include "flash.h" +#include "spi.h" + +#if FT2232_SPI_SUPPORT == 1 + +#include <ftdi.h> + +/* the 'H' chips can run internally at either 12Mhz or 60Mhz. + * the non-H chips can only run at 12Mhz. */ +#define CLOCK_5X 1 + +/* in either case, the divisor is a simple integer clock divider. + * if CLOCK_5X is set, this divisor divides 30Mhz, else it + * divides 6Mhz */ +#define DIVIDE_BY 3 // e.g. '3' will give either 10Mhz or 2Mhz spi clock + + +static struct ftdi_context ftdic_context; + +int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_write_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_write_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + +int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) +{ + int r; + r = ftdi_read_data(ftdic, (unsigned char *) buf, size); + if (r < 0) { + fprintf(stderr, "ftdi_read_data: %d, %s\n", r, + ftdi_get_error_string(ftdic)); + return 1; + } + return 0; +} + +int ft2232_spi_init(void) +{ + int f; + struct ftdi_context *ftdic = &ftdic_context; + unsigned char buf[512]; + unsigned char port_val = 0; + + + if (ftdi_init(ftdic) < 0) { + fprintf(stderr, "ftdi_init failed\n"); + return EXIT_FAILURE; + } + + // f = ftdi_usb_open(ftdic, 0x0403, 0x6010); // FT2232 + f = ftdi_usb_open(ftdic, 0x0403, 0x6011); // FT4232 + + if (f < 0 && f != -5) { + fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f, + ftdi_get_error_string(ftdic)); + exit(-1); + } + + if (ftdi_set_interface(ftdic, INTERFACE_B) < 0) { + fprintf(stderr, "unable to select FT2232 channel B: %s\n", + ftdic->error_str); + } + + if (ftdi_usb_reset(ftdic) < 0) { + fprintf(stderr, "unable to reset ftdi device\n"); + } + + if (ftdi_set_latency_timer(ftdic, 2) < 0) { + fprintf(stderr, "unable to set latency timer\n"); + } + + if (ftdi_write_data_set_chunksize(ftdic, 512)) { + fprintf(stderr, "unable to set chunk size\n"); + } + + if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) { + fprintf(stderr, "unable to set bitmode\n"); + } + +#if CLOCK_5X + printf_debug("disable divide-by-5 front stage\n"); + buf[0] = 0x8a; /* disable divide-by-5 */ + if (send_buf(ftdic, buf, 1)) + return -1; +#define MPSSE_CLK 60.0 + +#else + +#define MPSSE_CLK 12.0 + +#endif + printf_debug("set clock divisor\n"); + buf[0] = 0x86; /* command "set divisor" */ + /* valueL/valueH are (desired_divisor - 1) */ + buf[1] = (DIVIDE_BY-1) & 0xff; + buf[2] = ((DIVIDE_BY-1) >> 8) & 0xff; + if (send_buf(ftdic, buf, 3)) + return -1; + + printf("spi clock is %fMhz\n", + (double)(MPSSE_CLK / (((DIVIDE_BY-1) + 1) * 2))); + + /* Disconnect TDI/DO to TDO/DI for Loopback */ + printf_debug("no loopback of tdi/do tdo/di\n"); + buf[0] = 0x85; + if (send_buf(ftdic, buf, 1)) + return -1; + + printf_debug("set data bits\n"); + /* Set data bits low-byte command: + * value: 0x08 CS=high, DI=low, DO=low, SK=low + * dir: 0x0b CS=output, DI=input, DO=output, SK=output + */ +#define CS_BIT 0x08 + + buf[0] = SET_BITS_LOW; + buf[1] = (port_val = CS_BIT); + buf[2] = 0x0b; + if (send_buf(ftdic, buf, 3)) + return -1; + + printf_debug("\nft2232 chosen\n"); + + buses_supported = CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_FT2232; + + return 0; +} + +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + struct ftdi_context *ftdic = &ftdic_context; + static unsigned char *buf = NULL; + unsigned char port_val = 0; + int i, ret = 0; + + buf = realloc(buf, writecnt + readcnt + 100); + if (!buf) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + + i = 0; + + /* minimize USB transfers by packing as many commands + * as possible together. if we're not expecting to + * read, we can assert CS, write, and deassert CS all + * in one shot. if reading, we do three separate + * operations. */ + printf_debug("Assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = (port_val &= ~CS_BIT); + buf[i++] = 0x0b; + + if (writecnt) { + buf[i++] = 0x11; + buf[i++] = (writecnt - 1) & 0xff; + buf[i++] = ((writecnt - 1) >> 8) & 0xff; + memcpy(buf+i, writearr, writecnt); + i += writecnt; + } + + /* optionally terminate this batch of commands with a + * read command, then do the fetch of the results. + */ + if (readcnt) { + buf[i++] = 0x20; + buf[i++] = (readcnt - 1) & 0xff; + buf[i++] = ((readcnt - 1) >> 8) & 0xff; + ret = send_buf(ftdic, buf, i); + i = 0; + if (ret) goto deassert_cs; + + /* FIXME: This is unreliable. There's no guarantee that we read + * the response directly after sending the read command. + * We may be scheduled out etc. + */ + ret = get_buf(ftdic, readarr, readcnt); + + } + + deassert_cs: + printf_debug("de-assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = (port_val |= CS_BIT); + buf[i++] = 0x0b; + if (send_buf(ftdic, buf, i)) + return -1; + + return ret; +} + +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* Maximum read length is 64k bytes. */ + return spi_read_chunked(flash, buf, start, len, 64 * 1024); +} + +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) +{ + int total_size = 1024 * flash->total_size; + int i; + + printf_debug("total_size is %d\n", total_size); + for (i = 0; i < total_size; i += 256) { + int l, r; + if (i + 256 <= total_size) + l = 256; + else + l = total_size - i; + + spi_write_enable(); + if ((r = spi_nbyte_program(i, &buf[i], l))) { + fprintf(stderr, "%s: write fail %d\n", __FUNCTION__, r); + // spi_write_disable(); chip does this for us + return 1; + } + + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + /* loop */; + } + // spi_write_disable(); chip does this for us + + return 0; +} + +#else +int ft2232_spi_init(void) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} + +int ft2232_spi_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} + +int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} + +int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) +{ + fprintf(stderr, "FT2232 SPI support was not compiled in\n"); + exit(1); +} +#endif Index: flashrom-ftdi2232_spi/flashrom.c =================================================================== --- flashrom-ftdi2232_spi/flashrom.c (Revision 597) +++ flashrom-ftdi2232_spi/flashrom.c (Arbeitskopie) @@ -116,6 +116,22 @@ .delay = internal_delay, },
+ { + .init = ft2232_spi_init, + .shutdown = dummy_shutdown, + .map_flash_region = dummy_map, + .unmap_flash_region = dummy_unmap, + .chip_readb = dummy_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = dummy_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, + {}, };
@@ -589,7 +605,7 @@ " -i | --image <name>: only flash image name from flash layout\n" " -L | --list-supported: print supported devices\n" " -p | --programmer <name>: specify the programmer device\n" - " (internal, dummy, nic3com, satasii, it87spi)\n" + " (internal, dummy, nic3com, satasii, it87spi, ft2232spi)\n" " -h | --help: print this help text\n" " -R | --version: print the version (release)\n" "\nYou can specify one of -E, -r, -w, -v or no operation.\n" @@ -747,6 +763,8 @@ pcidev_bdf = strdup(optarg + 8); } else if (strncmp(optarg, "it87spi", 7) == 0) { programmer = PROGRAMMER_IT87SPI; + } else if (strncmp(optarg, "ft2232spi", 9) == 0) { + programmer = PROGRAMMER_FT2232SPI; } else { printf("Error: Unknown programmer.\n"); exit(1);
On Tue, Jun 16, 2009 at 01:42:33PM +0200, Carl-Daniel Hailfinger wrote:
On 12.06.2009 12:22, Carl-Daniel Hailfinger wrote:
This patch adds support for a new SPI programmer, based on the FT2232H/4232H chip from FTDI.
FTDI support is autodetected during compilation.
Paul writes: There are certainly possible improvements: The code has hard-coded values for which interface of the ftdi chip to use (interface B was chosen because libftdi seems to have trouble with A right now), what clock rate use for the SPI interface (I've been running at 30Mhz, but the patch sets it to 10Mhz), and possibly others. I think this means that per-programmer options might be a good idea at some point.
Carl-Daniel writes: There is one additional FIXME comment in the code, but AFAICS that problem is not solvable with current libftdi.
Signed-off-by: Paul Fox pgf@laptop.org Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Acked-by: Uwe Hermann uwe@hermann-uwe.de
Looks ok to me, builds fine with and without libftdi installed. There are some minor comments below, but those issues can be tackled in another patch.
Index: flashrom-ftdi2232_spi/Makefile
--- flashrom-ftdi2232_spi/Makefile (Revision 597) +++ flashrom-ftdi2232_spi/Makefile (Arbeitskopie)
Something here should be fixed probably, some of the tests are performed multiple times it seems and some printf's are confusing:
$ make Checking for a C compiler... found. Checking for FTDI support... not found. Checking for a C compiler... found. Checking for FTDI support... not found. Checking for pciutils and zlib... found. [...] $ make (again, after a successful build) Checking for a C compiler... found. Checking for FTDI support... not found. Checking for pciutils and zlib... found. $ make distclean Checking for a C compiler... found. Checking for FTDI support... not found. rm -f flashrom *.o rm -f .dependencies .features
With libftdi installed:
$ make Checking for a C compiler... found. Checking for FTDI support... found. Checking for a C compiler... found. Checking for FTDI support... found. Checking for pciutils and zlib... found. cc -Os -Wall -Werror -DFT2232_SPI_SUPPORT=1 -c chipset_enable.c -o chipset_enable.o [...] $ make Checking for a C compiler... found. Checking for FTDI support... found. Checking for pciutils and zlib... found. $ make distclean Checking for a C compiler... found. Checking for FTDI support... found. rm -f flashrom *.o rm -f .dependencies .features
@@ -22,6 +22,7 @@ CC ?= gcc STRIP = strip INSTALL = install +DIFF = diff
Please use space for indentation here as the other lines do.
Index: flashrom-ftdi2232_spi/ft2232_spi.c
--- flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) +++ flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) @@ -0,0 +1,288 @@ +/*
- This file is part of the flashrom project.
- Copyright (C) 2009 Paul Fox pgf@laptop.org
- Copyright (C) 2009 Carl-Daniel Hailfinger
- based initially on example program bitbang_ft2232.c from
- the libftdi-0.16 distribution, from:
- Intra2net AG opensource@intra2net.com
Please drop this, I can't spot any non-trivial amount of code which comes/remains from that file.
- // f = ftdi_usb_open(ftdic, 0x0403, 0x6010); // FT2232
- f = ftdi_usb_open(ftdic, 0x0403, 0x6011); // FT4232
Yep, this should be coupled with a command line option later, where the user specifies the USB IDs or the like.
- if (f < 0 && f != -5) {
fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f,
ftdi_get_error_string(ftdic));
Please start all messages to stdout or stderr with capital letter and end them with full stop for consistency, all other flashrom output does the same.
For stderr output we might also add "ERROR:" in front, at least for critical errors, dunno.
exit(-1);
- }
- if (ftdi_set_interface(ftdic, INTERFACE_B) < 0) {
fprintf(stderr, "unable to select FT2232 channel B: %s\n",
ftdic->error_str);
- }
- if (ftdi_usb_reset(ftdic) < 0) {
fprintf(stderr, "unable to reset ftdi device\n");
- }
There's no return or exit here, are these non-critical? Same for other such checks...
- if (ftdi_set_latency_timer(ftdic, 2) < 0) {
fprintf(stderr, "unable to set latency timer\n");
- }
- if (ftdi_write_data_set_chunksize(ftdic, 512)) {
fprintf(stderr, "unable to set chunk size\n");
- }
- if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) {
fprintf(stderr, "unable to set bitmode\n");
- }
- printf_debug("\nft2232 chosen\n");
This is a bit unclear, please make the message more usable.
@@ -589,7 +605,7 @@ " -i | --image <name>: only flash image name from flash layout\n" " -L | --list-supported: print supported devices\n" " -p | --programmer <name>: specify the programmer device\n"
" (internal, dummy, nic3com, satasii, it87spi)\n"
" (internal, dummy, nic3com, satasii, it87spi, ft2232spi)\n"
TODO: Document new programmer in manpage.
Uwe.
On 16.06.2009 19:44, Uwe Hermann wrote:
On Tue, Jun 16, 2009 at 01:42:33PM +0200, Carl-Daniel Hailfinger wrote:
On 12.06.2009 12:22, Carl-Daniel Hailfinger wrote:
This patch adds support for a new SPI programmer, based on the FT2232H/4232H chip from FTDI.
FTDI support is autodetected during compilation.
Paul writes: There are certainly possible improvements: The code has hard-coded values for which interface of the ftdi chip to use (interface B was chosen because libftdi seems to have trouble with A right now), what clock rate use for the SPI interface (I've been running at 30Mhz, but the patch sets it to 10Mhz), and possibly others. I think this means that per-programmer options might be a good idea at some point.
Carl-Daniel writes: There is one additional FIXME comment in the code, but AFAICS that problem is not solvable with current libftdi.
Signed-off-by: Paul Fox pgf@laptop.org Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Acked-by: Uwe Hermann uwe@hermann-uwe.de
Looks ok to me, builds fine with and without libftdi installed. There are some minor comments below, but those issues can be tackled in another patch.
Thanks!
Index: flashrom-ftdi2232_spi/Makefile
--- flashrom-ftdi2232_spi/Makefile (Revision 597) +++ flashrom-ftdi2232_spi/Makefile (Arbeitskopie)
Something here should be fixed probably, some of the tests are performed multiple times it seems and some printf's are confusing:
$ make Checking for a C compiler... found. Checking for FTDI support... not found. Checking for a C compiler... found. Checking for FTDI support... not found. Checking for pciutils and zlib... found. [...] $ make (again, after a successful build) Checking for a C compiler... found. Checking for FTDI support... not found. Checking for pciutils and zlib... found. $ make distclean Checking for a C compiler... found. Checking for FTDI support... not found. rm -f flashrom *.o rm -f .dependencies .features
With libftdi installed:
$ make Checking for a C compiler... found. Checking for FTDI support... found. Checking for a C compiler... found. Checking for FTDI support... found. Checking for pciutils and zlib... found. cc -Os -Wall -Werror -DFT2232_SPI_SUPPORT=1 -c chipset_enable.c -o chipset_enable.o [...] $ make Checking for a C compiler... found. Checking for FTDI support... found. Checking for pciutils and zlib... found. $ make distclean Checking for a C compiler... found. Checking for FTDI support... found. rm -f flashrom *.o rm -f .dependencies .features
Ah yes, that's an artifact of how the detection works. Basically, the main makefile includes a helper makefile (.features) which is generated by the features target. However, since that means .features is changed after make features, make restarts to read in the new file.
I have another version of the makefile patch, but it is really ugly. It does avoid the restart, though.
@@ -22,6 +22,7 @@ CC ?= gcc STRIP = strip INSTALL = install +DIFF = diff
Please use space for indentation here as the other lines do.
Done.
Index: flashrom-ftdi2232_spi/ft2232_spi.c
--- flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) +++ flashrom-ftdi2232_spi/ft2232_spi.c (Revision 0) @@ -0,0 +1,288 @@ +/*
- This file is part of the flashrom project.
- Copyright (C) 2009 Paul Fox pgf@laptop.org
- Copyright (C) 2009 Carl-Daniel Hailfinger
- based initially on example program bitbang_ft2232.c from
- the libftdi-0.16 distribution, from:
- Intra2net AG opensource@intra2net.com
Please drop this, I can't spot any non-trivial amount of code which comes/remains from that file.
Done.
- // f = ftdi_usb_open(ftdic, 0x0403, 0x6010); // FT2232
- f = ftdi_usb_open(ftdic, 0x0403, 0x6011); // FT4232
Yep, this should be coupled with a command line option later, where the user specifies the USB IDs or the like.
Yes, will be handled in a followup patch.
- if (f < 0 && f != -5) {
fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f,
ftdi_get_error_string(ftdic));
Please start all messages to stdout or stderr with capital letter and end them with full stop for consistency, all other flashrom output does the same.
Capital letter at the beginning: OK. Full stop at the end: Sorry, these are not sentences. The Linux kernel has no full stops at the end of its messages. Most other open source projects don't have full stops at the end of their messages. Actually, I'm thinging about removing all those full stops. It would certainly help reduce size of our binaries and of all logs by a few bytes.
For stderr output we might also add "ERROR:" in front, at least for critical errors, dunno.
Hm maybe. flashrom output is not consistent in this regard.
exit(-1);
- }
- if (ftdi_set_interface(ftdic, INTERFACE_B) < 0) {
fprintf(stderr, "unable to select FT2232 channel B: %s\n",
ftdic->error_str);
- }
- if (ftdi_usb_reset(ftdic) < 0) {
fprintf(stderr, "unable to reset ftdi device\n");
- }
There's no return or exit here, are these non-critical? Same for other such checks...
No idea. Paul?
- if (ftdi_set_latency_timer(ftdic, 2) < 0) {
fprintf(stderr, "unable to set latency timer\n");
- }
- if (ftdi_write_data_set_chunksize(ftdic, 512)) {
fprintf(stderr, "unable to set chunk size\n");
- }
- if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) {
fprintf(stderr, "unable to set bitmode\n");
- }
- printf_debug("\nft2232 chosen\n");
This is a bit unclear, please make the message more usable.
printf_debug is often unusable for everyone besides the original programmer. Maybe we could drop the message.
@@ -589,7 +605,7 @@ " -i | --image <name>: only flash image name from flash layout\n" " -L | --list-supported: print supported devices\n" " -p | --programmer <name>: specify the programmer device\n"
" (internal, dummy, nic3com, satasii, it87spi)\n"
" (internal, dummy, nic3com, satasii, it87spi, ft2232spi)\n"
TODO: Document new programmer in manpage.
Done.
Thanks for the review, committed in r598.
Regards, Carl-Daniel
carl-daniel wrote:
On 16.06.2009 19:44, Uwe Hermann wrote:
On Tue, Jun 16, 2009 at 01:42:33PM +0200, Carl-Daniel Hailfinger wrote:
On 12.06.2009 12:22, Carl-Daniel Hailfinger wrote:
This patch adds support for a new SPI programmer, based on the FT2232H/4232H chip from FTDI.
...
exit(-1);
- }
- if (ftdi_set_interface(ftdic, INTERFACE_B) < 0) {
fprintf(stderr, "unable to select FT2232 channel B: %s\n",
ftdic->error_str);
- }
- if (ftdi_usb_reset(ftdic) < 0) {
fprintf(stderr, "unable to reset ftdi device\n");
- }
There's no return or exit here, are these non-critical? Same for other such checks...
No idea. Paul?
i don't think continuing will be productive. this was an oversight. some of these calls, including the ones below, may not be mandatory for proper programming, but if the operation doesn't work, it indicates a communications or hardware problem. or a bug. in any case, we should fail.
- if (ftdi_set_latency_timer(ftdic, 2) < 0) {
fprintf(stderr, "unable to set latency timer\n");
- }
- if (ftdi_write_data_set_chunksize(ftdic, 512)) {
fprintf(stderr, "unable to set chunk size\n");
- }
- if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) {
fprintf(stderr, "unable to set bitmode\n");
- }
...
Thanks for the review, committed in r598.
thanks!
paul =--------------------- paul fox, pgf@foxharp.boston.ma.us (arlington, ma, where it's 62.6 degrees)
=--------------------- paul fox, pgf@foxharp.boston.ma.us (arlington, ma, where it's 62.6 degrees)
Cool! Not that it is related, but I am just north of you in NH :-)
Yup we haven't seen to many warm days yet this summer...