Add Bus Pirate SPI support to flashrom.
Untested, should work.
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006(a)gmx.net>
Index: flashrom-buspiratespi/flash.h
===================================================================
--- flashrom-buspiratespi/flash.h (Revision 767)
+++ flashrom-buspiratespi/flash.h (Arbeitskopie)
@@ -104,6 +104,9 @@
#if SERPROG_SUPPORT == 1
PROGRAMMER_SERPROG,
#endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+ PROGRAMMER_BUSPIRATESPI,
+#endif
PROGRAMMER_INVALID /* This must always be the last entry. */
};
@@ -484,6 +487,12 @@
int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf);
+/* buspirate_spi.c */
+int buspirate_spi_init(void);
+int buspirate_spi_shutdown(void);
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+
/* flashrom.c */
extern char *programmer_param;
extern int verbose;
@@ -527,6 +536,9 @@
#if DUMMY_SUPPORT == 1
SPI_CONTROLLER_DUMMY,
#endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+ SPI_CONTROLLER_BUSPIRATE,
+#endif
SPI_CONTROLLER_INVALID /* This must always be the last entry. */
};
extern const int spi_programmer_count;
@@ -736,5 +748,8 @@
uint8_t serprog_chip_readb(const chipaddr addr);
void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
void serprog_delay(int delay);
+void sp_flush_incoming(void);
+int sp_openserport(char *dev, unsigned int baud);
+extern int sp_fd;
#endif /* !__FLASH_H__ */
Index: flashrom-buspiratespi/buspirate_spi.c
===================================================================
--- flashrom-buspiratespi/buspirate_spi.c (Revision 0)
+++ flashrom-buspiratespi/buspirate_spi.c (Revision 0)
@@ -0,0 +1,317 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * 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 <ctype.h>
+#include <fcntl.h>
+#include "flash.h"
+#include "spi.h"
+
+int buspirate_serialport_setup(char *dev)
+{
+ /* 115200bps, 8 databits, no parity, 1 stopbit */
+ sp_fd = sp_openserport(dev, 115200);
+ return 0;
+}
+
+int buspirate_serialport_shutdown(void)
+{
+ close(sp_fd);
+ return 0;
+}
+
+int serialport_write(unsigned char *buf, unsigned int writecnt)
+{
+ int tmp = 0;
+
+ while (tmp != writecnt) {
+ tmp = write(sp_fd, buf + tmp, writecnt - tmp);
+ if (tmp == -1)
+ return 1;
+ if (!tmp)
+ printf_debug("Empty write\n");
+ }
+
+ return 0;
+}
+
+int serialport_read(unsigned char *buf, unsigned int readcnt)
+{
+ int tmp = 0;
+
+ while (tmp != readcnt) {
+ tmp = read(sp_fd, buf + tmp, readcnt - tmp);
+ if (tmp == -1)
+ return 1;
+ if (!tmp)
+ printf_debug("Empty read\n");
+ }
+
+ return 0;
+}
+
+int buspirate_discard_read(void)
+{
+ int flags;
+
+ printf_debug("%s\n", __func__);
+ flags = fcntl(sp_fd, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(sp_fd, F_SETFL, flags);
+ sp_flush_incoming();
+ flags &= ~O_NONBLOCK;
+ fcntl(sp_fd, F_SETFL, flags);
+
+ return 0;
+}
+
+#undef FAKE_COMMUNICATION
+int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
+{
+ int i, ret = 0;
+
+ printf_debug("%s: write %i, read %i\n", __func__, writecnt, readcnt);
+ if (!writecnt && !readcnt) {
+ fprintf(stderr, "Zero length command!\n");
+ return 1;
+ }
+ printf_debug("Sending");
+ for (i = 0; i < writecnt; i++)
+ printf_debug(" 0x%02x", buf[i]);
+#ifdef FAKE_COMMUNICATION
+ /* Placate the caller for now. */
+ buf[0] = 0x01;
+ memset(buf + 1, 0xff, readcnt - 1);
+ ret = 0;
+#else
+ if (writecnt)
+ ret = serialport_write(buf, writecnt);
+ if (ret)
+ return ret;
+ if (readcnt)
+ ret = serialport_read(buf, readcnt);
+ if (ret)
+ return ret;
+#endif
+ printf_debug(", receiving");
+ for (i = 0; i < readcnt; i++)
+ printf_debug(" 0x%02x", buf[i]);
+ printf_debug("\n");
+ return 0;
+}
+
+int buspirate_spi_init(void)
+{
+ unsigned char buf[512];
+ int ret = 0;
+ int i;
+ char *devpos = NULL;
+ char *dev = NULL;
+ int devlen;
+
+ if (programmer_param && !strlen(programmer_param)) {
+ free(programmer_param);
+ programmer_param = NULL;
+ }
+ if (programmer_param) {
+ devpos = strstr(programmer_param, "dev=");
+ if (devpos) {
+ devpos += 4;
+ devlen = strcspn(devpos, ",:");
+ if (devlen) {
+ dev = malloc(devlen + 1);
+ if (!dev) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1);
+ }
+ strncpy(dev, devpos, devlen);
+ dev[devlen] = '\0';
+ }
+ }
+ free(programmer_param);
+ programmer_param = NULL;
+ }
+ if (!dev) {
+ fprintf(stderr, "No serial device given. Use flashrom -p "
+ "buspiratespi:dev=/dev/ttyUSB0\n");
+ return 1;
+ }
+
+ ret = buspirate_serialport_setup(dev);
+ if (ret)
+ return ret;
+
+ /* This is the brute force version, but it should work. */
+ for (i = 0; i < 19; i++) {
+ /* Enter raw bitbang mode */
+ buf[0] = 0x00;
+ /* Send the command, don't read the response. */
+ ret = buspirate_sendrecv(buf, 1, 0);
+ if (ret)
+ return ret;
+ /* Read any response and discard it. */
+ ret = buspirate_discard_read();
+ if (ret)
+ return ret;
+ }
+ /* Enter raw bitbang mode */
+ buf[0] = 0x00;
+ ret = buspirate_sendrecv(buf, 1, 5);
+ if (ret)
+ return ret;
+ if (memcmp(buf, "BBIO", 4)) {
+ fprintf(stderr, "Entering raw bitbang mode failed!\n");
+ return 1;
+ }
+ printf_debug("Raw bitbang mode version %c\n", buf[4]);
+ if (buf[4] != '1') {
+ fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
+ buf[4]);
+ return 1;
+ }
+ /* Enter raw SPI mode */
+ buf[0] = 0x01;
+ ret = buspirate_sendrecv(buf, 1, 4);
+ if (memcmp(buf, "SPI", 3)) {
+ fprintf(stderr, "Entering raw SPI mode failed!\n");
+ return 1;
+ }
+ printf_debug("Raw SPI mode version %c\n", buf[3]);
+ if (buf[3] != '1') {
+ fprintf(stderr, "Can't handle raw SPI mode version %c!\n",
+ buf[3]);
+ return 1;
+ }
+
+ /* Initial setup: Enable power, */
+ /* De-assert CS# */
+ buf[0] = 0x03;
+ ret = buspirate_sendrecv(buf, 1, 1);
+ if (ret)
+ return 1;
+ if (buf[0] != 0x01) {
+ fprintf(stderr, "Protocol error!\n");
+ return 1;
+ }
+
+ buses_supported = CHIP_BUSTYPE_SPI;
+ spi_controller = SPI_CONTROLLER_BUSPIRATE;
+
+ return 0;
+}
+
+int buspirate_spi_shutdown(void)
+{
+ unsigned char buf[5];
+ int ret = 0;
+
+ /* Exit raw SPI mode (enter raw bitbang mode) */
+ buf[0] = 0x00;
+ ret = buspirate_sendrecv(buf, 1, 5);
+ if (ret)
+ return ret;
+ if (memcmp(buf, "BBIO", 4)) {
+ fprintf(stderr, "Entering raw bitbang mode failed!\n");
+ return 1;
+ }
+ printf_debug("Raw bitbang mode version %c\n", buf[4]);
+ if (buf[4] != '1') {
+ fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
+ buf[4]);
+ return 1;
+ }
+ /* Reset Bus Pirate (return to user terminal) */
+ buf[0] = 0x0f;
+ ret = buspirate_sendrecv(buf, 1, 0);
+ if (ret)
+ return ret;
+
+ /* Shut down serial port communication */
+ ret = buspirate_serialport_shutdown();
+ if (ret)
+ return ret;
+ printf_debug("Bus Pirate shutdown completed.\n");
+
+ return 0;
+}
+
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ static unsigned char *buf = NULL;
+ int i = 0, ret = 0;
+
+ if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
+ return SPI_INVALID_LENGTH;
+
+ /* +2 is pretty arbitrary. */
+ buf = realloc(buf, writecnt + readcnt + 2);
+ if (!buf) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); // -1
+ }
+
+ /* Assert CS# */
+ buf[i++] = 0x02;
+ ret = buspirate_sendrecv(buf, 1, 1);
+ if (ret)
+ return SPI_GENERIC_ERROR;
+ if (buf[0] != 0x01) {
+ fprintf(stderr, "Protocol error!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ i = 0;
+ buf[i++] = 0x10 | (writecnt + readcnt - 1);
+ memcpy(buf + i, writearr, writecnt);
+ i += writecnt;
+ memset(buf + i, 0, readcnt);
+ ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt);
+ if (ret)
+ return SPI_GENERIC_ERROR;
+ if (buf[0] != 0x01) {
+ fprintf(stderr, "Protocol error!\n");
+ return SPI_GENERIC_ERROR;
+ }
+ memcpy(readarr, buf + i, readcnt);
+
+ i = 0;
+ /* De-assert CS# */
+ buf[i++] = 0x03;
+ ret = buspirate_sendrecv(buf, 1, 1);
+ if (ret)
+ return SPI_GENERIC_ERROR;
+ if (buf[0] != 0x01) {
+ fprintf(stderr, "Protocol error!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ return ret;
+}
+
+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+ /* Maximum read length is 12 bytes, use 8 for now. */
+ return spi_read_chunked(flash, buf, start, len, 8);
+}
+
+/* We could do 12-byte writes, but for now we use the generic 1-byte code. */
Index: flashrom-buspiratespi/serprog.c
===================================================================
--- flashrom-buspiratespi/serprog.c (Revision 767)
+++ flashrom-buspiratespi/serprog.c (Arbeitskopie)
@@ -61,7 +61,7 @@
#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */
#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */
-static int sp_fd;
+int sp_fd;
static uint16_t sp_device_serbuf_size = 16;
static uint16_t sp_device_opbuf_size = 300;
@@ -185,7 +185,7 @@
{0, 0} /* Terminator */
};
-static int sp_openserport(char *dev, unsigned int baud)
+int sp_openserport(char *dev, unsigned int baud)
{
struct termios options;
int fd, i;
@@ -208,20 +208,16 @@
break;
}
}
- options.c_cflag &= ~PARENB;
- options.c_cflag &= ~CSTOPB;
- options.c_cflag &= ~CSIZE;
- options.c_cflag |= CS8;
- options.c_cflag &= ~CRTSCTS;
+ options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
+ options.c_cflag |= (CS8 | CLOCAL | CREAD);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
options.c_oflag &= ~OPOST;
- options.c_cflag |= (CLOCAL | CREAD);
tcsetattr(fd, TCSANOW, &options);
return fd;
}
-static void sp_flush_incoming(void)
+void sp_flush_incoming(void)
{
int i;
for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */
Index: flashrom-buspiratespi/spi.c
===================================================================
--- flashrom-buspiratespi/spi.c (Revision 767)
+++ flashrom-buspiratespi/spi.c (Arbeitskopie)
@@ -100,6 +100,15 @@
},
#endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+ { /* SPI_CONTROLLER_BUSPIRATE */
+ .command = buspirate_spi_send_command,
+ .multicommand = default_spi_send_multicommand,
+ .read = buspirate_spi_read,
+ .write_256 = spi_chip_write_1,
+ },
+#endif
+
{}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */
};
Index: flashrom-buspiratespi/Makefile
===================================================================
--- flashrom-buspiratespi/Makefile (Revision 767)
+++ flashrom-buspiratespi/Makefile (Arbeitskopie)
@@ -89,6 +89,9 @@
# Always enable Dr. Kaiser for now.
CONFIG_DRKAISER ?= yes
+# Always enable Bus Pirate SPI for now.
+CONFIG_BUSPIRATESPI ?= yes
+
# Disable wiki printing by default. It is only useful if you have wiki access.
CONFIG_PRINT_WIKI ?= no
@@ -138,6 +141,11 @@
OBJS += drkaiser.o
endif
+ifeq ($(CONFIG_BUSPIRATESPI), yes)
+FEATURE_CFLAGS += -D'BUSPIRATE_SPI_SUPPORT=1'
+OBJS += buspirate_spi.o
+endif
+
ifeq ($(CONFIG_PRINT_WIKI), yes)
FEATURE_CFLAGS += -D'PRINT_WIKI_SUPPORT=1'
OBJS += print_wiki.o
Index: flashrom-buspiratespi/spi.h
===================================================================
--- flashrom-buspiratespi/spi.h (Revision 767)
+++ flashrom-buspiratespi/spi.h (Arbeitskopie)
@@ -106,6 +106,7 @@
#define JEDEC_BYTE_PROGRAM_INSIZE 0x00
/* Error codes */
+#define SPI_GENERIC_ERROR -1
#define SPI_INVALID_OPCODE -2
#define SPI_INVALID_ADDRESS -3
#define SPI_INVALID_LENGTH -4
Index: flashrom-buspiratespi/flashrom.c
===================================================================
--- flashrom-buspiratespi/flashrom.c (Revision 767)
+++ flashrom-buspiratespi/flashrom.c (Arbeitskopie)
@@ -204,6 +204,25 @@
},
#endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+ {
+ .name = "buspiratespi",
+ .init = buspirate_spi_init,
+ .shutdown = buspirate_spi_shutdown,
+ .map_flash_region = fallback_map,
+ .unmap_flash_region = fallback_unmap,
+ .chip_readb = noop_chip_readb,
+ .chip_readw = fallback_chip_readw,
+ .chip_readl = fallback_chip_readl,
+ .chip_readn = fallback_chip_readn,
+ .chip_writeb = noop_chip_writeb,
+ .chip_writew = fallback_chip_writew,
+ .chip_writel = fallback_chip_writel,
+ .chip_writen = fallback_chip_writen,
+ .delay = internal_delay,
+ },
+#endif
+
{}, /* This entry corresponds to PROGRAMMER_INVALID. */
};
--
Developer quote of the month:
"We are juggling too many chainsaws and flaming arrows and tigers."