1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-30 00:13:43 +02:00

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.

Corresponding to flashrom svn r598.

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>
This commit is contained in:
Paul Fox 2009-06-16 21:08:06 +00:00 committed by Carl-Daniel Hailfinger
parent 4cb7a96153
commit 05dfbe67d6
6 changed files with 349 additions and 9 deletions

View File

@ -22,6 +22,7 @@ PROGRAM = flashrom
CC ?= gcc CC ?= gcc
STRIP = strip STRIP = strip
INSTALL = install INSTALL = install
DIFF = diff
PREFIX ?= /usr/local PREFIX ?= /usr/local
MANDIR ?= $(PREFIX)/share/man MANDIR ?= $(PREFIX)/share/man
CFLAGS ?= -Os -Wall -Werror CFLAGS ?= -Os -Wall -Werror
@ -48,9 +49,9 @@ OBJS = chipset_enable.o board_enable.o udelay.o jedec.o stm50flw0x0x.o \
sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \ 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 \ 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 \ 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 # Set the flashrom version string from the highest revision number
# of the checked out flashrom files. # of the checked out flashrom files.
@ -63,16 +64,19 @@ VERSION := 0.9.0-r$(SVNVERSION)
SVNDEF := -D'FLASHROM_VERSION="$(VERSION)"' SVNDEF := -D'FLASHROM_VERSION="$(VERSION)"'
$(PROGRAM): $(OBJS) $(PROGRAM): $(OBJS)
$(CC) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LIBS) $(CC) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LIBS) $(FEATURE_LIBS)
flashrom.o: flashrom.c 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: clean:
rm -f $(PROGRAM) *.o rm -f $(PROGRAM) *.o
distclean: clean distclean: clean
rm -f .dependencies rm -f .dependencies .features
dep: dep:
@$(CC) $(CPPFLAGS) $(SVNDEF) -MM *.c > .dependencies @$(CC) $(CPPFLAGS) $(SVNDEF) -MM *.c > .dependencies
@ -81,7 +85,7 @@ strip: $(PROGRAM)
$(STRIP) $(STRIP_ARGS) $(PROGRAM) $(STRIP) $(STRIP_ARGS) $(PROGRAM)
compiler: compiler:
@echo; printf "Checking for a C compiler... " @printf "Checking for a C compiler... "
@$(shell ( echo "int main(int argc, char **argv)"; \ @$(shell ( echo "int main(int argc, char **argv)"; \
echo "{ return 0; }"; ) > .test.c ) echo "{ return 0; }"; ) > .test.c )
@$(CC) $(CFLAGS) $(LDFLAGS) .test.c -o .test >/dev/null && \ @$(CC) $(CFLAGS) $(LDFLAGS) .test.c -o .test >/dev/null && \
@ -89,8 +93,10 @@ compiler:
rm -f .test.c .test; exit 1) rm -f .test.c .test; exit 1)
@rm -f .test.c .test @rm -f .test.c .test
pciutils: compiler # We don't specify compiler as requirement because the compiler is already
@echo; printf "Checking for pciutils and zlib... " # checked during makefile remake through .features
pciutils:
@printf "Checking for pciutils and zlib... "
@$(shell ( echo "#include <pci/pci.h>"; \ @$(shell ( echo "#include <pci/pci.h>"; \
echo "struct pci_access *pacc;"; \ echo "struct pci_access *pacc;"; \
echo "int main(int argc, char **argv)"; \ echo "int main(int argc, char **argv)"; \
@ -102,6 +108,19 @@ pciutils: compiler
rm -f .test.c .test; exit 1) rm -f .test.c .test; exit 1)
@rm -f .test.c .test @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) install: $(PROGRAM)
mkdir -p $(DESTDIR)$(PREFIX)/sbin mkdir -p $(DESTDIR)$(PREFIX)/sbin
mkdir -p $(DESTDIR)$(MANDIR)/man8 mkdir -p $(DESTDIR)$(MANDIR)/man8
@ -122,3 +141,4 @@ tarball: export
.PHONY: all clean distclean dep compiler pciutils export tarball .PHONY: all clean distclean dep compiler pciutils export tarball
-include .dependencies -include .dependencies
-include .features

View File

@ -86,6 +86,7 @@ extern int programmer;
#define PROGRAMMER_NIC3COM 0x02 #define PROGRAMMER_NIC3COM 0x02
#define PROGRAMMER_SATASII 0x03 #define PROGRAMMER_SATASII 0x03
#define PROGRAMMER_IT87SPI 0x04 #define PROGRAMMER_IT87SPI 0x04
#define PROGRAMMER_FT2232SPI 0x05
struct programmer_entry { struct programmer_entry {
const char *vendor; const char *vendor;
@ -358,6 +359,13 @@ void satasii_chip_writeb(uint8_t val, chipaddr addr);
uint8_t satasii_chip_readb(const chipaddr addr); uint8_t satasii_chip_readb(const chipaddr addr);
extern struct pcidev_status satas_sii[]; 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 */ /* flashrom.c */
extern int verbose; extern int verbose;
#define printf_debug(x...) { if (verbose) printf(x); } #define printf_debug(x...) { if (verbose) printf(x); }
@ -388,6 +396,7 @@ enum spi_controller {
SPI_CONTROLLER_SB600, SPI_CONTROLLER_SB600,
SPI_CONTROLLER_VIA, SPI_CONTROLLER_VIA,
SPI_CONTROLLER_WBSIO, SPI_CONTROLLER_WBSIO,
SPI_CONTROLLER_FT2232,
SPI_CONTROLLER_DUMMY, SPI_CONTROLLER_DUMMY,
}; };
extern enum spi_controller spi_controller; extern enum spi_controller spi_controller;

View File

@ -136,6 +136,8 @@ Specify the programmer device. Currently supported are:
.sp .sp
.BR "* it87spi" " (for flash ROMs behind an ITE IT87xx Super I/O LPC/SPI translation unit)" .BR "* it87spi" " (for flash ROMs behind an ITE IT87xx Super I/O LPC/SPI translation unit)"
.sp .sp
.BR "* ft2232spi" " (for flash ROMs attached to a FT2232H/FT4232H based USB SPI programmer)"
.sp
The dummy programmer has an optional parameter specifying the bus types it The dummy programmer has an optional parameter specifying the bus types it
should support. For that you have to use the should support. For that you have to use the
.B "flashrom -p dummy=type" .B "flashrom -p dummy=type"

View File

@ -116,6 +116,22 @@ const struct programmer_entry programmer_table[] = {
.delay = internal_delay, .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 @@ void usage(const char *name)
" -i | --image <name>: only flash image name from flash layout\n" " -i | --image <name>: only flash image name from flash layout\n"
" -L | --list-supported: print supported devices\n" " -L | --list-supported: print supported devices\n"
" -p | --programmer <name>: specify the programmer device\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" " -h | --help: print this help text\n"
" -R | --version: print the version (release)\n" " -R | --version: print the version (release)\n"
"\nYou can specify one of -E, -r, -w, -v or no operation.\n" "\nYou can specify one of -E, -r, -w, -v or no operation.\n"
@ -747,6 +763,8 @@ int main(int argc, char *argv[])
pcidev_bdf = strdup(optarg + 8); pcidev_bdf = strdup(optarg + 8);
} else if (strncmp(optarg, "it87spi", 7) == 0) { } else if (strncmp(optarg, "it87spi", 7) == 0) {
programmer = PROGRAMMER_IT87SPI; programmer = PROGRAMMER_IT87SPI;
} else if (strncmp(optarg, "ft2232spi", 9) == 0) {
programmer = PROGRAMMER_FT2232SPI;
} else { } else {
printf("Error: Unknown programmer.\n"); printf("Error: Unknown programmer.\n");
exit(1); exit(1);

284
ft2232_spi.c Normal file
View File

@ -0,0 +1,284 @@
/*
* This file is part of the flashrom project.
*
* Copyright (C) 2009 Paul Fox <pgf@laptop.org>
* Copyright (C) 2009 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
*/
#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

7
spi.c
View File

@ -47,6 +47,8 @@ int spi_command(unsigned int writecnt, unsigned int readcnt,
return sb600_spi_command(writecnt, readcnt, writearr, readarr); return sb600_spi_command(writecnt, readcnt, writearr, readarr);
case SPI_CONTROLLER_WBSIO: case SPI_CONTROLLER_WBSIO:
return wbsio_spi_command(writecnt, readcnt, writearr, readarr); return wbsio_spi_command(writecnt, readcnt, writearr, readarr);
case SPI_CONTROLLER_FT2232:
return ft2232_spi_command(writecnt, readcnt, writearr, readarr);
case SPI_CONTROLLER_DUMMY: case SPI_CONTROLLER_DUMMY:
return dummy_spi_command(writecnt, readcnt, writearr, readarr); return dummy_spi_command(writecnt, readcnt, writearr, readarr);
default: default:
@ -212,6 +214,7 @@ int probe_spi_rdid4(struct flashchip *flash)
case SPI_CONTROLLER_VIA: case SPI_CONTROLLER_VIA:
case SPI_CONTROLLER_SB600: case SPI_CONTROLLER_SB600:
case SPI_CONTROLLER_WBSIO: case SPI_CONTROLLER_WBSIO:
case SPI_CONTROLLER_FT2232:
case SPI_CONTROLLER_DUMMY: case SPI_CONTROLLER_DUMMY:
return probe_spi_rdid_generic(flash, 4); return probe_spi_rdid_generic(flash, 4);
default: default:
@ -726,6 +729,8 @@ int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
return ich_spi_read(flash, buf, start, len); return ich_spi_read(flash, buf, start, len);
case SPI_CONTROLLER_WBSIO: case SPI_CONTROLLER_WBSIO:
return wbsio_spi_read(flash, buf, start, len); return wbsio_spi_read(flash, buf, start, len);
case SPI_CONTROLLER_FT2232:
return ft2232_spi_read(flash, buf, start, len);
default: default:
printf_debug printf_debug
("%s called, but no SPI chipset/strapping detected\n", ("%s called, but no SPI chipset/strapping detected\n",
@ -774,6 +779,8 @@ int spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
return ich_spi_write_256(flash, buf); return ich_spi_write_256(flash, buf);
case SPI_CONTROLLER_WBSIO: case SPI_CONTROLLER_WBSIO:
return wbsio_spi_write_1(flash, buf); return wbsio_spi_write_1(flash, buf);
case SPI_CONTROLLER_FT2232:
return ft2232_spi_write_256(flash, buf);
default: default:
printf_debug printf_debug
("%s called, but no SPI chipset/strapping detected\n", ("%s called, but no SPI chipset/strapping detected\n",