This is the bitbanging SPI driver infrastructure.
If you want support for a particular piece of hardware, just fill in a few functions in spi_bitbang_master_table. That's it. On top of this, the RayeR SPI flasher should be supportable in ~20 LOC.
Tested, trace looks OK.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-bitbang_spi/flash.h =================================================================== --- flashrom-bitbang_spi/flash.h (Revision 731) +++ flashrom-bitbang_spi/flash.h (Arbeitskopie) @@ -145,6 +145,21 @@ void chip_readn(uint8_t *buf, const chipaddr addr, size_t len); void programmer_delay(int usecs);
+enum spi_bitbang_master { + SPI_BITBANG_INVALID /* This must always be the last entry. */ +}; + +extern const int spi_bitbang_master_count; + +extern enum spi_bitbang_master spi_bitbang_master; + +struct spi_bitbang_master_entry { + void (*set_cs) (int val); + void (*set_sck) (int val); + void (*set_mosi) (int val); + int (*get_miso) (void); +}; + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
enum chipbustype { @@ -444,6 +459,14 @@ int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf);
+/* bitbang_spi.c */ +extern int bitbang_half_period; +extern const struct spi_bitbang_master_entry spi_bitbang_master_table[]; +int bitbang_spi_init(void); +int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +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); + /* flashrom.c */ extern char *programmer_param; extern int verbose; Index: flashrom-bitbang_spi/bitbang_spi.c =================================================================== --- flashrom-bitbang_spi/bitbang_spi.c (Revision 0) +++ flashrom-bitbang_spi/bitbang_spi.c (Revision 0) @@ -0,0 +1,161 @@ +/* + * 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 "flash.h" +#include "spi.h" + +/* Length of half a clock period in usecs */ +int bitbang_half_period = 0; + +enum spi_bitbang_master spi_bitbang_master = SPI_BITBANG_INVALID; + +const struct spi_bitbang_master_entry spi_bitbang_master_table[] = { + {}, /* This entry corresponds to SPI_BITBANG_INVALID. */ +}; + +const int spi_bitbang_master_count = ARRAY_SIZE(spi_bitbang_master_table); + +void bitbang_set_cs(int val) +{ + spi_bitbang_master_table[spi_bitbang_master].set_cs(val); +} + +void bitbang_set_sck(int val) +{ + spi_bitbang_master_table[spi_bitbang_master].set_sck(val); +} + +void bitbang_set_mosi(int val) +{ + spi_bitbang_master_table[spi_bitbang_master].set_mosi(val); +} + +int bitbang_get_miso(void) +{ + return spi_bitbang_master_table[spi_bitbang_master].get_miso(); +} + +int bitbang_spi_init(void) +{ + bitbang_set_cs(1); + bitbang_set_sck(0); + buses_supported = CHIP_BUSTYPE_SPI; + return 0; +} + +uint8_t bitbang_spi_readwrite_byte(uint8_t val) +{ + uint8_t ret = 0; + int i; + + for (i = 7; i >= 0; i--) { + bitbang_set_mosi((val >> i) & 1); + programmer_delay(bitbang_half_period); + bitbang_set_sck(1); + ret <<= 1; + ret |= bitbang_get_miso(); + programmer_delay(bitbang_half_period); + bitbang_set_sck(0); + } + return ret; +} + +int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + static unsigned char *bufout = NULL; + static unsigned char *bufin = NULL; + static int oldbufsize = 0; + int bufsize = max(writecnt + readcnt, 260); + int i; + + /* Arbitrary size limitation here. We're only constrained by memory. */ + if (writecnt > 65536 || readcnt > 65536) + return SPI_INVALID_LENGTH; + + if (bufsize != oldbufsize) { + bufout = realloc(bufout, bufsize); + if (!bufout) { + fprintf(stderr, "Out of memory!\n"); + if (bufin) + free(bufin); + exit(1); + } + bufin = realloc(bufout, bufsize); + if (!bufin) { + fprintf(stderr, "Out of memory!\n"); + if (bufout) + free(bufout); + exit(1); + } + } + + memcpy(bufout, writearr, writecnt); + /* Shift out 0x00 while reading data. */ + memset(bufout + writecnt, 0x00, readcnt); + /* Make sure any non-read data is 0xff. */ + memset(bufin + writecnt, 0xff, readcnt); + + bitbang_set_cs(0); + for (i = 0; i < readcnt + writecnt; i++) { + bufin[i] = bitbang_spi_readwrite_byte(bufout[i]); + } + programmer_delay(bitbang_half_period); + bitbang_set_cs(1); + programmer_delay(bitbang_half_period); + memcpy(readarr, bufin + writecnt, readcnt); + + return 0; +} + +int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* Maximum read length is unlimited, use 64k bytes. */ + return spi_read_chunked(flash, buf, start, len, 64 * 1024); +} + +int bitbang_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; + + if ((r = spi_nbyte_program(i, &buf[i], l))) { + fprintf(stderr, "%s: write fail %d\n", __FUNCTION__, r); + return 1; + } + + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + /* loop */; + } + + return 0; +} Index: flashrom-bitbang_spi/Makefile =================================================================== --- flashrom-bitbang_spi/Makefile (Revision 731) +++ flashrom-bitbang_spi/Makefile (Arbeitskopie) @@ -68,6 +68,9 @@ # Always enable serprog for now. Needs to be disabled on Windows. CONFIG_SERPROG ?= yes
+# Bitbanging SPI infrastructure is not used yet. +CONFIG_BITBANG_SPI ?= no + # Always enable 3Com NICs for now. CONFIG_NIC3COM ?= yes
@@ -94,6 +97,11 @@ endif endif
+ifeq ($(CONFIG_BITBANG_SPI), yes) +FEATURE_CFLAGS += -D'BITBANG_SPI_SUPPORT=1' +OBJS += bitbang_spi.o +endif + ifeq ($(CONFIG_NIC3COM), yes) FEATURE_CFLAGS += -D'NIC3COM_SUPPORT=1' OBJS += nic3com.o Index: flashrom-bitbang_spi/flashrom.c =================================================================== --- flashrom-bitbang_spi/flashrom.c (Revision 731) +++ flashrom-bitbang_spi/flashrom.c (Arbeitskopie) @@ -693,6 +693,12 @@ fprintf(stderr, "SPI programmer table miscompilation!\n"); exit(1); } +#if BITBANG_SPI_SUPPORT == 1 + if (spi_bitbang_master_count - 1 != SPI_BITBANG_INVALID) { + fprintf(stderr, "Bitbanging SPI master table miscompilation!\n"); + exit(1); + } +#endif
setbuf(stdout, NULL); while ((opt = getopt_long(argc, argv, optstring,