[flashrom] [PATCH] Bus Pirate SPI support in flashrom

Sean Nelson audiohacked at gmail.com
Tue Nov 24 01:09:10 CET 2009


The Bus Pirate code works, but flashrom might hang if the chip has a
"personal" problem; none of the Bus Pirate's fault.
I think it has to do with the chip not being reset, internally.

Chip tested: Sanyo LF25FW203{T,A}

Acked-by: Sean Nelson <audiohacked at gmail.com>

On Mon, Nov 23, 2009 at 3:24 PM, Carl-Daniel Hailfinger
<c-d.hailfinger.devel.2006 at gmx.net> wrote:
> Add Bus Pirate SPI support to flashrom.
>
> The code should work on Linux/*BSD/MacOSX and relies on the serial code
> implementation in serial.c. Support for additional platforms (Windows)
> will have to be added to serial.c for this to work. For tests without a
> Bus Pirate (or with non-functional serial code) it is possible to
> #define FAKE_COMMUNICATION in buspirate_spi.c.
> Thanks to Sean Nelson for the SPI mode settings code. I tweaked it a bit
> to make configuration from a commandline easier should anybody want that
> feature.
>
> Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>
> Acked-by: Stefan Reinauer <stepan at coresystems.de>
>
> Index: flashrom-buspiratespi/flash.h
> ===================================================================
> --- flashrom-buspiratespi/flash.h       (Revision 771)
> +++ 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;
> Index: flashrom-buspiratespi/buspirate_spi.c
> ===================================================================
> --- flashrom-buspiratespi/buspirate_spi.c       (Revision 0)
> +++ flashrom-buspiratespi/buspirate_spi.c       (Revision 0)
> @@ -0,0 +1,358 @@
> +/*
> + * 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"
> +
> +/* Change this to #define if you want to test without a serial implementation */
> +#undef FAKE_COMMUNICATION
> +
> +#ifndef FAKE_COMMUNICATION
> +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;
> +}
> +#else
> +#define buspirate_serialport_setup(...) 0
> +#define buspirate_serialport_shutdown(...) 0
> +#define serialport_write(...) 0
> +#define serialport_read(...) 0
> +#define buspirate_discard_read(...) 0
> +#endif
> +
> +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. */
> +       if (readcnt) {
> +               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 (SPI peripherals config): Enable power, CS high, AUX */
> +       buf[0] = 0x40 | 0xb;
> +       ret = buspirate_sendrecv(buf, 1, 1);
> +       if (ret)
> +               return 1;
> +       if (buf[0] != 0x01) {
> +               fprintf(stderr, "Protocol error while setting power/CS/AUX!\n");
> +               return 1;
> +       }
> +
> +       /* Set speed to 8 MHz */
> +       buf[0] = 0x60 | 0x7;
> +       ret = buspirate_sendrecv(buf, 1, 1);
> +       if (ret)
> +               return 1;
> +       if (buf[0] != 0x01) {
> +               fprintf(stderr, "Protocol error while setting SPI speed!\n");
> +               return 1;
> +       }
> +
> +       /* Set SPI config: output type, idle, clock edge, sample */
> +       buf[0] = 0x80 | 0xa;
> +       ret = buspirate_sendrecv(buf, 1, 1);
> +       if (ret)
> +               return 1;
> +       if (buf[0] != 0x01) {
> +               fprintf(stderr, "Protocol error while setting SPI config!\n");
> +               return 1;
> +       }
> +
> +       /* De-assert CS# */
> +       buf[0] = 0x03;
> +       ret = buspirate_sendrecv(buf, 1, 1);
> +       if (ret)
> +               return 1;
> +       if (buf[0] != 0x01) {
> +               fprintf(stderr, "Protocol error while raising CS#!\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 while lowering CS#!\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 while reading/writing SPI!\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 while raising CS#!\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/spi.c
> ===================================================================
> --- flashrom-buspiratespi/spi.c (Revision 771)
> +++ 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 771)
> +++ flashrom-buspiratespi/Makefile      (Arbeitskopie)
> @@ -25,7 +25,7 @@
>  DIFF    = diff
>  PREFIX  ?= /usr/local
>  MANDIR  ?= $(PREFIX)/share/man
> -CFLAGS  ?= -Os -Wall -Werror
> +CFLAGS  ?= -Os -Wall -Werror -g
>  EXPORTDIR ?= .
>
>  OS_ARCH        = $(shell uname)
> @@ -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,9 +141,19 @@
>  OBJS += drkaiser.o
>  endif
>
> +ifeq ($(CONFIG_BUSPIRATESPI), yes)
> +FEATURE_CFLAGS += -D'BUSPIRATE_SPI_SUPPORT=1'
> +OBJS += buspirate_spi.o
> +endif
> +
> +# Ugly, but there's no elif/elseif.
>  ifeq ($(CONFIG_SERPROG), yes)
>  OBJS += serial.o
> +else
> +ifeq ($(CONFIG_BUSPIRATESPI), yes)
> +OBJS += serial.o
>  endif
> +endif
>
>  ifeq ($(CONFIG_PRINT_WIKI), yes)
>  FEATURE_CFLAGS += -D'PRINT_WIKI_SUPPORT=1'
> Index: flashrom-buspiratespi/spi.h
> ===================================================================
> --- flashrom-buspiratespi/spi.h (Revision 771)
> +++ 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 771)
> +++ 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."
>
>




More information about the flashrom mailing list